36 #include "DGtal/base/Common.h"
37 #include "DGtal/helpers/StdDefs.h"
39 #include "DGtal/shapes/ShapeFactory.h"
40 #include "DGtal/shapes/Shapes.h"
41 #include "DGtal/topology/helpers/Surfaces.h"
44 #include "DGtal/images/imagesSetsUtils/ImageFromSet.h"
45 #include "DGtal/images/imagesSetsUtils/SetFromImage.h"
46 #include "DGtal/images/ImageContainerBySTLVector.h"
47 #include "DGtal/images/ImageSelector.h"
48 #include "DGtal/io/readers/PointListReader.h"
49 #include "DGtal/io/readers/TableReader.h"
50 #include "DGtal/io/Color.h"
52 #include "DGtal/io/readers/GenericReader.h"
55 #include "DGtal/geometry/curves/FreemanChain.h"
58 #include "DGtal/geometry/curves/ArithmeticalDSSComputer.h"
59 #include "DGtal/geometry/curves/GreedySegmentation.h"
60 #include "DGtal/geometry/curves/SaturatedSegmentation.h"
61 #include "DGtal/geometry/curves/FP.h"
62 #include "DGtal/geometry/curves/StabbingCircleComputer.h"
63 #include "DGtal/geometry/curves/SaturatedSegmentation.h"
64 #include "DGtal/geometry/curves/SegmentComputerUtils.h"
66 #include "DGtal/io/boards/Board2D.h"
67 #include "DGtal/io/boards/CDrawableWithBoard2D.h"
71 using namespace DGtal;
152 int main(
int argc,
char** argv )
157 app.description(
"Display discrete contours. \n Basic example: \t displayContours [options] --input <fileName>");
158 std::string inputFileName;
159 std::string outputFileName {
"result.svg"};
160 std::string inputSDFileName;
161 std::string inputSFPFileName;
162 std::string processingName;
163 unsigned int indexPoint;
164 double pointSize {0.0};
165 double scaleVectorField {1.0};
166 bool fillContour {
false};
167 bool rotateVectorField {
false};
168 bool outputStreamEPS {
false};
169 bool outputStreamSVG {
false};
170 bool outputStreamFIG {
false};
171 bool noXFIGHeader {
false};
172 bool invertYaxis {
false};
173 double alphaBG {1.0};
174 double lineWidth {0.0};
176 unsigned int vectorFromAngle {0};
177 std::string displayVectorField =
"";
178 std::vector <unsigned int> vectorFieldIndex = {0,1};
179 std::string backgroundImage;
181 app.add_option(
"-i,--input,1", inputFileName,
"input FreemanChain file name" )
183 ->check(CLI::ExistingFile);
184 app.add_option(
"--outputFile,-o", outputFileName,
"save output file automatically according the file format extension.");
186 CLI::Option* optSDP = app.add_option(
"--SDP",inputSDFileName,
"Import a contour as a Sequence of Discrete Points (SDP format)")
187 ->check(CLI::ExistingFile);
188 app.add_option(
"--SFP",inputSFPFileName,
"mport a contour as a Sequence of Floating Points (SFP format)")
189 ->check(CLI::ExistingFile);
190 app.add_option(
"--drawContourPoint", pointSize,
"<size> display contour points as disk of radius <size>");
191 app.add_flag(
"--fillContour", fillContour,
"fill the contours with default color (gray)");
192 app.add_option(
"--lineWidth", lineWidth,
"Define the linewidth of the contour (SDP format)" );
193 auto indexPointOpt = app.add_option(
"--drawPointOfIndex,-f", indexPoint,
" Draw the contour point of index." );
194 app.add_option(
"--pointSize", pointSize,
"<size> Set the display point size of the point displayed by drawPointofIndex option (default 2.0) " );
195 app.add_option(
"--noXFIGHeader", noXFIGHeader,
"to exclude xfig header in the resulting output stream (no effect with option -outputFile).");
197 app.add_option(
"--withProcessing",processingName,
"Processing (used only when the input is a Freeman chain (--input)):\n\t DSS segmentation {DSS}\n\t Maximal segments {MS}\n\t Faithful Polygon {FP}\n\t Minimum Length Polygon {MLP}" )
198 -> check(CLI::IsMember({
"MS",
"FP",
"MLP"}));
200 app.add_option(
"--displayVectorField,-v", displayVectorField,
"Add the display of a vector field represented by two floating coordinates. Each vector is displayed starting from the corresponding contour point coordinates.");
201 app.add_option(
"--scaleVectorField",scaleVectorField,
"set the scale of the vector field (default 1) (used with --displayVectorField).",
true);
202 app.add_option(
"--vectorFieldIndex", vectorFieldIndex ,
"specify the vector field index (by default 0,1) (used with --displayVectorField).",
true)
205 auto optVFAngke = app.add_option(
"--vectorFromAngle", vectorFromAngle,
"specify that the vectors are defined from an angle value represented at the given index (by default 0) (used with --displayVectorField).");
206 app.add_flag(
"--rotateVectorField", rotateVectorField,
"apply a CCW rotation of 90° (used with --displayVectorField). ");
207 app.add_flag(
"--outputStreamEPS",
" specify eps for output stream format.");
208 app.add_flag(
"--outputStreamSVG",
" specify svg for output stream format.");
209 app.add_flag(
"--outputStreamFIG",
" specify fig for output stream format.");
210 app.add_flag(
"--invertYaxis", invertYaxis,
" invertYaxis invert the Y axis for display contours (used only with --SDP)")
212 app.add_option(
"--backgroundImage", backgroundImage,
"backgroundImage <filename> : display image as background ")
213 ->check(CLI::ExistingFile);
214 app.add_option(
"--alphaBG", alphaBG,
"alphaBG <value> 0-1.0 to display the background image in transparency (default 1.0), (transparency works only if cairo is available)",
true);
215 app.add_option(
"--scale", scale,
"scale <value> 1: normal; >1 : larger ; <1 lower resolutions)",
true);
219 app.get_formatter()->column_width(40);
220 CLI11_PARSE(app, argc, argv);
225 trace.info() << app.get_description() << std::endl;
226 trace.error() <<
"You need at least add one input file using -i, --SDP, --SFP (see --help for more details)" << std::endl;
231 aBoard.setUnit (0.05*scale, LibBoard::Board::UCentimeter);
233 if(backgroundImage !=
"")
235 typedef ImageSelector<Z2i::Domain, unsigned char>::Type Image;
236 Image img = DGtal::GenericReader<Image>::import( backgroundImage );
237 Z2i::Point ptInf = img.domain().lowerBound();
238 Z2i::Point ptSup = img.domain().upperBound();
239 unsigned int width = abs(ptSup[0]-ptInf[0]+1);
240 unsigned int height = abs(ptSup[1]-ptInf[1]+1);
241 aBoard.drawImage(backgroundImage, 0-0.5,height-0.5, width, height, -1, alphaBG);
244 if(inputFileName !=
""){
245 std::vector< FreemanChain<int> > vectFc = PointListReader< Z2i::Point>:: getFreemanChainsFromFile<int> (inputFileName);
246 aBoard << CustomStyle( vectFc.at(0).className(),
247 new CustomColors( Color::Red , fillContour? Color::Gray: Color::None ) );
248 aBoard.setLineWidth (lineWidth);
249 for(
unsigned int i=0; i<vectFc.size(); i++){
250 aBoard << vectFc.at(i) ;
251 if( indexPointOpt->count() != 0 ){
252 aBoard.setPenColor(Color::Blue);
253 aBoard.fillCircle((
double)(vectFc.at(i).getPoint(indexPoint)[0]),
254 (
double)(vectFc.at(i).getPoint(indexPoint)[1]), pointSize);
257 if(processingName !=
""){
258 std::vector<Z2i::Point> vPts(vectFc.at(i).size()+1);
259 copy ( vectFc.at(i).begin(), vectFc.at(i).end(), vPts.begin() );
261 if ( vPts.at(0) == vPts.at(vPts.size()-1) )
269 if (processingName ==
"DSS")
271 typedef ArithmeticalDSSComputer<std::vector<Z2i::Point>::iterator,int,4> DSS4;
272 typedef GreedySegmentation<DSS4> Decomposition4;
275 Decomposition4 theDecomposition( vPts.begin(),vPts.end(),computer );
278 std::string className;
279 for ( Decomposition4::SegmentComputerIterator it = theDecomposition.begin();
280 it != theDecomposition.end(); ++it )
282 DSS4::Primitive segment(it->primitive());
284 aBoard << SetMode( segment.className(),
"BoundingBox" );
285 className = segment.className() +
"/BoundingBox";
286 aBoard << CustomStyle( className,
287 new CustomPenColor( DGtal::Color::Gray ) );
291 }
else if (processingName ==
"MS") {
293 typedef ArithmeticalDSSComputer<std::vector<Z2i::Point>::iterator,int,4> DSS4;
294 typedef SaturatedSegmentation<DSS4> Decomposition4;
298 Decomposition4 theDecomposition( vPts.begin(),vPts.end(),computer );
301 std::string className;
302 for ( Decomposition4::SegmentComputerIterator it = theDecomposition.begin();
303 it != theDecomposition.end(); ++it )
305 DSS4::Primitive segment(it->primitive());
306 aBoard << SetMode( segment.className(),
"BoundingBox" );
307 className = segment.className() +
"/BoundingBox";
308 aBoard << CustomStyle( className,
309 new CustomPenColor( DGtal::Color::Gray ) );
313 }
else if (processingName ==
"FP")
315 typedef FP<std::vector<Z2i::Point>::iterator,int,4> FP;
316 FP theFP( vPts.begin(),vPts.end() );
317 aBoard << CustomStyle( theFP.className(),
318 new CustomPenColor( DGtal::Color::Black ) );
321 }
else if (processingName ==
"MLP")
323 typedef FP<std::vector<Z2i::Point>::iterator,int,4> FP;
324 FP theFP( vPts.begin(),vPts.end() );
326 std::vector<FP::RealPoint> v( theFP.size() );
327 theFP.copyMLP( v.begin() );
330 std::vector<LibBoard::Point> polyline;
331 std::vector<FP::RealPoint>::const_iterator it = v.begin();
332 for ( ;it != v.end();++it)
334 FP::RealPoint p = (*it);
335 polyline.push_back(LibBoard::Point(p[0],p[1]));
339 FP::RealPoint p = (*v.begin());
340 polyline.push_back(LibBoard::Point(p[0],p[1]));
342 aBoard.setPenColor(DGtal::Color::Black);
343 aBoard.drawPolyline(polyline);
345 }
else if (processingName ==
"MDCA")
347 typedef KhalimskySpaceND<2,int> KSpace;
348 typedef GridCurve<KSpace> Curve;
350 curve.initFromPointsVector( vPts );
351 typedef Curve::IncidentPointsRange Range;
352 Range r = curve.getIncidentPointsRange();
353 typedef Range::ConstCirculator ConstCirculator;
354 typedef StabbingCircleComputer<ConstCirculator> SegmentComputer;
356 typedef SaturatedSegmentation<SegmentComputer> Segmentation;
358 Segmentation theSegmentation( r.c(), r.c(), SegmentComputer() );
359 theSegmentation.setMode(
"Last");
361 Segmentation::SegmentComputerIterator it = theSegmentation.begin();
362 Segmentation::SegmentComputerIterator itEnd = theSegmentation.end();
364 otherBoard.setPenColor(DGtal::Color::Black);
366 for ( ; it != itEnd; ++it )
368 aBoard << SetMode(SegmentComputer().className(),
"") << (*it);
369 otherBoard << SetMode(SegmentComputer().className(),
"") << (*it);
371 otherBoard.saveSVG(
"mdca.svg", Board2D::BoundingBox, 5000 );
379 if( inputSDFileName !=
"" || inputSFPFileName !=
"" )
381 std::vector<LibBoard::Point> contourPt;
382 if( inputSDFileName !=
"" )
384 std::vector< Z2i::Point > contour = PointListReader< Z2i::Point >::getPointsFromFile(inputSDFileName);
385 for(
unsigned int j=0; j<contour.size(); j++)
387 LibBoard::Point pt((
double)(contour.at(j)[0]),
388 (invertYaxis? (
double)(-contour.at(j)[1]+contour.at(0)[1]):(
double)(contour.at(j)[1])));
389 contourPt.push_back(pt);
392 aBoard.fillCircle(pt.x, pt.y, pointSize);
397 if( inputSFPFileName !=
"" )
399 std::vector< PointVector<2,double> > contour =
400 PointListReader< PointVector<2,double> >::getPointsFromFile(inputSFPFileName);
401 for(
unsigned int j=0; j<contour.size(); j++)
403 LibBoard::Point pt((
double)(contour.at(j)[0]),
404 (invertYaxis? (
double)(-contour.at(j)[1]+contour.at(0)[1]):(
double)(contour.at(j)[1])));
405 contourPt.push_back(pt);
408 aBoard.fillCircle(pt.x, pt.y, pointSize);
413 aBoard.setPenColor(Color::Red);
414 aBoard.setFillColor(Color::Gray);
415 aBoard.setLineStyle (LibBoard::Shape::SolidStyle );
416 aBoard.setLineWidth (lineWidth);
419 aBoard.drawPolyline(contourPt);
422 aBoard.fillPolyline(contourPt);
424 if( indexPointOpt->count() != 0 )
426 aBoard.fillCircle((
double)(contourPt.at(indexPoint).x), (
double)(contourPt.at(indexPoint).y), pointSize);
431 if(displayVectorField !=
"")
433 std::vector< PointVector<2,double> > vField;
434 if(optVFAngke->count() != 0)
437 std::vector<double> vAngles = TableReader<double>::getColumnElementsFromFile(displayVectorField, vectorFromAngle);
438 for(
unsigned int i = 0; i < vAngles.size(); i++)
440 vField.push_back(Z2i::RealPoint(cos(vAngles[i]),sin(vAngles[i])));
445 vField = PointListReader< PointVector<2,double> >::getPointsFromFile(displayVectorField, vectorFieldIndex);
447 for(
unsigned int i = 0; i< contourPt.size(); i++)
449 vField[i] = vField[i].getNormalized();
450 auto p = contourPt[i];
451 if(!rotateVectorField)
453 aBoard.drawArrow(p.x, p.y, p.x+vField[i][0]*scaleVectorField, p.y+vField[i][1]*scaleVectorField );
457 aBoard.drawArrow(p.x, p.y, p.x-vField[i][1]*scaleVectorField, p.y+vField[i][0]*scaleVectorField );
466 if( outputFileName !=
"" )
468 std::string extension = outputFileName.substr(outputFileName.find_last_of(
".") + 1);
471 aBoard.saveSVG(outputFileName.c_str());
475 if (extension==
"eps")
477 aBoard.saveCairo(outputFileName.c_str(),Board2D::CairoEPS );
479 else if (extension==
"pdf")
481 aBoard.saveCairo(outputFileName.c_str(),Board2D::CairoPDF );
483 else if (extension==
"png")
485 aBoard.saveCairo(outputFileName.c_str(),Board2D::CairoPNG );
488 else if(extension==
"eps")
490 aBoard.saveEPS(outputFileName.c_str());
492 else if(extension==
"fig")
494 aBoard.saveFIG(outputFileName.c_str(),LibBoard::Board::BoundingBox, 10.0, !noXFIGHeader );
500 aBoard.saveSVG(std::cout);
502 else if (outputStreamFIG)
504 aBoard.saveFIG(std::cout, LibBoard::Board::BoundingBox, 10.0, !noXFIGHeader);
505 }
else if (outputStreamEPS)
507 aBoard.saveEPS(std::cout);