40#include "DGtal/base/Common.h"
41#include "DGtal/kernel/domains/HyperRectDomain.h"
43#include "DGtal/shapes/ShapeFactory.h"
44#include "DGtal/shapes/Shapes.h"
45#include "DGtal/helpers/StdDefs.h"
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"
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"
62#include "DGtal/topology/helpers/Surfaces.h"
148std::vector<std::string> shapes2D;
149std::vector<std::string> shapesDesc;
150std::vector<std::string> shapesParam1;
151std::vector<std::string> shapesParam2;
152std::vector<std::string> shapesParam3;
153std::vector<std::string> shapesParam4;
162 shapes2D.push_back(
"ball");
163 shapesDesc.push_back(
"Ball for the Euclidean metric.");
164 shapesParam1.push_back(
"--radius [-R]");
165 shapesParam2.push_back(
"");
166 shapesParam3.push_back(
"");
167 shapesParam4.push_back(
"");
169 shapes2D.push_back(
"square");
170 shapesDesc.push_back(
"square (no signature).");
171 shapesParam1.push_back(
"--width [-w]");
172 shapesParam2.push_back(
"");
173 shapesParam3.push_back(
"");
174 shapesParam4.push_back(
"");
176 shapes2D.push_back(
"lpball");
177 shapesDesc.push_back(
"Ball for the l_power metric (no signature).");
178 shapesParam1.push_back(
"--radius [-R],");
179 shapesParam2.push_back(
"--power [-p]");
180 shapesParam3.push_back(
"");
181 shapesParam4.push_back(
"");
183 shapes2D.push_back(
"flower");
184 shapesDesc.push_back(
"Flower with k petals with radius ranging from R+/-v.");
185 shapesParam1.push_back(
"--radius [-R],");
186 shapesParam2.push_back(
"--varsmallradius [-v],");
187 shapesParam3.push_back(
"--k [-k],");
188 shapesParam4.push_back(
"--phi");
190 shapes2D.push_back(
"ngon");
191 shapesDesc.push_back(
"Regular k-gon.");
192 shapesParam1.push_back(
"--radius [-R],");
193 shapesParam2.push_back(
"--k [-k],");
194 shapesParam3.push_back(
"--phi");
195 shapesParam4.push_back(
"");
197 shapes2D.push_back(
"accflower");
198 shapesDesc.push_back(
"Accelerated Flower with k petals.");
199 shapesParam1.push_back(
"--radius [-R],");
200 shapesParam2.push_back(
"--varsmallradius [-v],");
201 shapesParam3.push_back(
"--k [-k],");
202 shapesParam4.push_back(
"--phi");
204 shapes2D.push_back(
"ellipse");
205 shapesDesc.push_back(
"Ellipse.");
206 shapesParam1.push_back(
"--axis1 [-A],");
207 shapesParam2.push_back(
"--axis2 [-a],");
208 shapesParam3.push_back(
"--phi");
209 shapesParam4.push_back(
"");
218 trace.emphase()<<
"2D Shapes:"<<std::endl;
219 for(
unsigned int i=0; i<shapes2D.size(); ++i)
220 trace.info()<<
"\t"<<shapes2D[i]<<
"\t"
221 << shapesDesc[i]<<std::endl
222 <<
"\t\tRequired parameter(s): "
223 << shapesParam1[i]<<
" "
224 << shapesParam2[i]<<
" "
225 << shapesParam3[i]<<
" "
226 << shapesParam4[i]<<std::endl;
238unsigned int checkAndReturnIndex(
const std::string &shapeName)
242 while ((pos < shapes2D.size()) && (shapes2D[pos] != shapeName))
245 if (pos == shapes2D.size())
247 trace.error() <<
"The specified shape has not found.";
248 trace.info()<<std::endl;
267template <
typename Shape,
typename Range,
typename Po
int,
typename Quantity>
269estimateGeometry(Shape& s,
272 std::vector<Point>& points,
273 std::vector<Point>& tangents,
274 std::vector<Quantity>& curvatures) {
276 typedef typename Range::ConstIterator ConstIterator;
277 for (ConstIterator i = r.begin(); i != r.end(); ++i)
284 typedef typename Range::ConstCirculator ConstCirculator;
286 typedef ParametricShapeTangentFunctor< Shape > TangentFunctor;
287 TrueLocalEstimatorOnPoints< ConstCirculator, Shape, TangentFunctor >
288 trueTangentEstimator;
289 trueTangentEstimator.attach( s );
290 trueTangentEstimator.eval( r.c(), r.c(), std::back_inserter(tangents), h );
292 typedef ParametricShapeCurvatureFunctor< Shape > CurvatureFunctor;
293 TrueLocalEstimatorOnPoints< ConstCirculator, Shape, CurvatureFunctor >
294 trueCurvatureEstimator;
295 trueCurvatureEstimator.attach( s );
296 trueCurvatureEstimator.eval( r.c(), r.c(), std::back_inserter(curvatures), h );
299template <
typename Space,
typename Shape>
304 const std::string & outputFormat,
306 const std::string & outputFileName )
309 typedef typename Space::Point Point;
310 typedef typename Space::Vector Vector;
311 typedef typename Space::RealPoint RealPoint;
312 typedef typename Space::Integer Integer;
313 typedef HyperRectDomain<Space> Domain;
314 typedef KhalimskySpaceND<Space::dimension,Integer> KSpace;
315 typedef typename KSpace::SCell SCell;
316 typedef typename GridCurve<KSpace>::PointsRange Range;
317 typedef typename Range::ConstIterator ConstIteratorOnPoints;
318 typedef typename GridCurve<KSpace>::MidPointsRange MidPointsRange;
321 GaussDigitizer<Space,Shape> dig;
322 dig.attach( aShape );
323 Vector vlow(-1,-1); Vector vup(1,1);
324 dig.init( aShape.getLowerBound()+vlow, aShape.getUpperBound()+vup, h );
325 Domain domain = dig.getDomain();
328 bool ok = K.init( dig.getLowerBound(), dig.getUpperBound(),
true );
331 std::cerr <<
"[generateContour]"
332 <<
" error in creating KSpace." << std::endl;
338 SurfelAdjacency<KSpace::dimension> SAdj(
true );
339 SCell bel = Surfaces<KSpace>::findABel( K, dig, 10000 );
341 std::vector<Point> points;
342 Surfaces<KSpace>::track2DBoundaryPoints( points, K, SAdj, dig, bel );
344 GridCurve<KSpace> gridcurve;
345 gridcurve.initFromPointsVector( points );
347 Range r = gridcurve.getPointsRange();
349 if ( outputFormat ==
"pts" )
351 for ( ConstIteratorOnPoints it = r.begin(), it_end = r.end();
355 std::cout << p[ 0 ] <<
" " << p[ 1 ] << std::endl;
358 else if ( outputFormat ==
"fc" )
360 ConstIteratorOnPoints it = r.begin();
362 std::cout << p[ 0 ] <<
" " << p[ 1 ] <<
" ";
363 for ( ConstIteratorOnPoints it_end = r.end(); it != it_end; ++it )
367 if ( v[0 ]== 1 ) std::cout <<
'0';
368 if ( v[ 1 ] == 1 ) std::cout <<
'1';
369 if ( v[ 0 ] == -1 ) std::cout <<
'2';
370 if ( v[ 1 ] == -1 ) std::cout <<
'3';
374 Point p2= *(r.begin());
376 if ( v.norm1() == 1 )
378 if ( v[ 0 ] == 1 ) std::cout <<
'0';
379 if ( v[ 1 ] == 1 ) std::cout <<
'1';
380 if ( v[ 0 ] == -1 ) std::cout <<
'2';
381 if ( v[ 1 ] == -1 ) std::cout <<
'3';
383 std::cout << std::endl;
390 s << outputFileName <<
".geom";
391 std::ofstream outstream(s.str().c_str());
392 if (!outstream.is_open())
return false;
395 outstream <<
"# " << outputFileName << std::endl;
396 outstream <<
"# Pointel (x,y), Midpoint of the following linel (x',y')" << std::endl;
397 outstream <<
"# id x y tangentx tangenty curvaturexy"
398 <<
" x' y' tangentx' tangenty' curvaturex'y'" << std::endl;
400 std::vector<RealPoint> truePoints, truePoints2;
401 std::vector<RealPoint> trueTangents, trueTangents2;
402 std::vector<double> trueCurvatures, trueCurvatures2;
404 estimateGeometry<Shape, Range, RealPoint, double>
405 (aShape, h, r, truePoints, trueTangents, trueCurvatures);
407 estimateGeometry<Shape, MidPointsRange, RealPoint, double>
408 (aShape, h, gridcurve.getMidPointsRange(), truePoints2, trueTangents2, trueCurvatures2);
411 unsigned int n = (
unsigned int)r.size();
412 for (
unsigned int i = 0; i < n; ++i )
414 outstream << std::setprecision( 15 ) << i
415 <<
" " << truePoints[ i ][ 0 ]
416 <<
" " << truePoints[ i ][ 1 ]
417 <<
" " << trueTangents[ i ][ 0 ]
418 <<
" " << trueTangents[ i ][ 1 ]
419 <<
" " << trueCurvatures[ i ]
420 <<
" " << truePoints2[ i ][ 0 ]
421 <<
" " << truePoints2[ i ][ 1 ]
422 <<
" " << trueTangents2[ i ][ 0 ]
423 <<
" " << trueTangents2[ i ][ 1 ]
424 <<
" " << trueCurvatures2[ i ]
434 catch ( InputException e )
436 std::cerr <<
"[generateContour]"
437 <<
" error in finding a bel." << std::endl;
448void missingParam(std::string param)
450 trace.error() <<
" Parameter: "<<param<<
" is required..";
451 trace.info()<<std::endl;
457int main(
int argc,
char** argv )
461 std::string shapeName;
462 std::string outputFileName;
463 std::string outputFormat {
"pts"};
466 double smallradius {5};
467 double varsmallradius {5};
468 double cx {0.0}, cy {0.0};
475 app.description(
"Generates multigrid contours of 2d digital shapes using DGtal library.\n Typical use example:\n \t contourGenerator --shape <shapeName> [requiredParam] [otherOptions]\n");
476 auto listOpt = app.add_flag(
"--list,-l",
"List all available shapes");
477 auto shapeNameOpt = app.add_option(
"--shape,-s", shapeName,
"Shape name");
478 auto radiusOpt = app.add_option(
"--radius,-R", radius,
"Radius of the shape" );
479 auto axis1Opt = app.add_option(
"--axis1,-A", axis1,
"Half big axis of the shape (ellipse)" );
480 auto axis2Opt = app.add_option(
"--axis2,-a", axis2,
"Half small axis of the shape (ellipse)" );
481 auto smallradiusOpt = app.add_option(
"--smallradius,-r", smallradius,
"Small radius of the shape (default 5)");
482 auto varsmallradiusOpt = app.add_option(
"--varsmallradius,-v", varsmallradius,
"Variable small radius of the shape (default 5)" );
483 auto kOpt = app.add_option(
"-k", k,
"Number of branches or corners the shape (default 3)" );
484 auto phiOpt = app.add_option(
"--phi", phi,
"Phase of the shape (in radian, default 0.0)" );
485 auto widthOpt = app.add_option(
"--width,-w", width,
"Width of the shape (default 10.0)" );
486 auto powerOpt = app.add_option(
"--power,-p", power,
"Power of the metric (default 2.0)" );
487 app.add_option(
"--center_x,-x", cx,
"x-coordinate of the shape center (default 0.0)" );
488 app.add_option(
"--center_y,-y", cy,
"y-coordinate of the shape center (default 0.0)" );
489 app.add_option(
"--gridstep,-g", h,
"Gridstep for the digitization (default 1.0)" );
490 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)");
491 auto outputFileNameOpt = app.add_option(
"--outputGeometry,-o", outputFileName,
"Base name of the file containing the shape geometry (points, tangents, curvature)" );
493 app.get_formatter()->column_width(40);
494 CLI11_PARSE(app, argc, argv);
500 if ( listOpt->count() > 0 )
506 if(shapeNameOpt->count()==0) missingParam(
"--shape");
507 bool withGeom =
true;
508 if (outputFileNameOpt->count()==0) withGeom =
false;
511 unsigned int id = checkAndReturnIndex(shapeName);
514 typedef Z2i::Space Space;
515 typedef Space::RealPoint RealPoint;
517 RealPoint center( cx, cy );
521 if (radiusOpt->count()==0) missingParam(
"--radius");
522 Ball2D<Space> ball(Z2i::Point(0,0), radius);
523 generateContour<Space>( ball, h, outputFormat, withGeom, outputFileName );
528 ImplicitHyperCube<Space> object(Z2i::Point(0,0), width/2);
529 trace.error()<<
"Not available.";
530 trace.info()<<std::endl;
535 if (radiusOpt->count()==0) missingParam(
"--radius");
536 ImplicitRoundedHyperCube<Space> ball(Z2i::Point(0,0), radius, power);
537 trace.error()<<
"Not available.";
538 trace.info()<<std::endl;
543 if (radiusOpt->count()==0) missingParam(
"--radius");
546 Flower2D<Space> flower( center, radius, varsmallradius, k, phi );
547 generateContour<Space>( flower, h, outputFormat, withGeom, outputFileName );
551 if (radiusOpt->count()==0) missingParam(
"--radius");
554 NGon2D<Space> object( center, radius, k, phi );
555 generateContour<Space>(
object, h, outputFormat, withGeom, outputFileName );
560 if (radiusOpt->count()==0) missingParam(
"--radius");
563 AccFlower2D<Space> accflower( center, radius, varsmallradius, k, phi );
564 generateContour<Space>( accflower, h, outputFormat, withGeom, outputFileName );
568 if (axis1Opt->count()==0) missingParam(
"--axis1");
569 if (axis2Opt->count()==0) missingParam(
"--axis2");
571 Ellipse2D<Space> ellipse( center, axis1, axis2, phi );
572 generateContour<Space>( ellipse, h, outputFormat, withGeom, outputFileName );