DGtalTools  1.2.0
displayContours.cpp
1 
30 #include <iostream>
31 
32 //STL
33 #include <vector>
34 #include <string>
35 
36 #include "DGtal/base/Common.h"
37 #include "DGtal/helpers/StdDefs.h"
38 
39 #include "DGtal/shapes/ShapeFactory.h"
40 #include "DGtal/shapes/Shapes.h"
41 #include "DGtal/topology/helpers/Surfaces.h"
42 
43 //image
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"
51 
52 #include "DGtal/io/readers/GenericReader.h"
53 
54 //contour
55 #include "DGtal/geometry/curves/FreemanChain.h"
56 
57 //processing
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"
65 
66 #include "DGtal/io/boards/Board2D.h"
67 #include "DGtal/io/boards/CDrawableWithBoard2D.h"
68 
69 #include "CLI11.hpp"
70 
71 using namespace DGtal;
72 
73 
74 
152 int main( int argc, char** argv )
153 {
154 
155  // parse command line using CLI ----------------------------------------------
156  CLI::App app;
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};
175  double scale {1.0};
176  unsigned int vectorFromAngle {0};
177  std::string displayVectorField = "";
178  std::vector <unsigned int> vectorFieldIndex = {0,1};
179  std::string backgroundImage;
180 
181  app.add_option("-i,--input,1", inputFileName, "input FreemanChain file name" )
182  ->required()
183  ->check(CLI::ExistingFile);
184  app.add_option("--outputFile,-o", outputFileName, "save output file automatically according the file format extension.");
185 
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).");
196 
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"}));
199 
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)
203  ->expected(2);
204 
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)")
211  ->needs(optSDP);
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);
216 
217 
218 
219  app.get_formatter()->column_width(40);
220  CLI11_PARSE(app, argc, argv);
221  // END parse command line using CLI ----------------------------------------------
222 
223  if (argc == 1 )
224  {
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;
227  return EXIT_FAILURE;
228  }
229 
230  Board2D aBoard;
231  aBoard.setUnit (0.05*scale, LibBoard::Board::UCentimeter);
232 
233  if(backgroundImage != "")
234  {
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);
242  }
243 
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);
255  }
256 
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() );
260  bool isClosed;
261  if ( vPts.at(0) == vPts.at(vPts.size()-1) )
262  {
263  isClosed = true;
264  vPts.pop_back();
265  }
266  else
267  isClosed = false;
268 
269  if (processingName == "DSS")
270  {
271  typedef ArithmeticalDSSComputer<std::vector<Z2i::Point>::iterator,int,4> DSS4;
272  typedef GreedySegmentation<DSS4> Decomposition4;
273 
274  DSS4 computer;
275  Decomposition4 theDecomposition( vPts.begin(),vPts.end(),computer );
276 
277  //for each segment
278  std::string className;
279  for ( Decomposition4::SegmentComputerIterator it = theDecomposition.begin();
280  it != theDecomposition.end(); ++it )
281  {
282  DSS4::Primitive segment(it->primitive());
283 
284  aBoard << SetMode( segment.className(), "BoundingBox" );
285  className = segment.className() + "/BoundingBox";
286  aBoard << CustomStyle( className,
287  new CustomPenColor( DGtal::Color::Gray ) );
288  aBoard << segment; // draw each segment
289  }
290 
291  } else if (processingName == "MS") {
292 
293  typedef ArithmeticalDSSComputer<std::vector<Z2i::Point>::iterator,int,4> DSS4;
294  typedef SaturatedSegmentation<DSS4> Decomposition4;
295 
296  //Segmentation
297  DSS4 computer;
298  Decomposition4 theDecomposition( vPts.begin(),vPts.end(),computer );
299 
300  //for each segment
301  std::string className;
302  for ( Decomposition4::SegmentComputerIterator it = theDecomposition.begin();
303  it != theDecomposition.end(); ++it )
304  {
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 ) );
310  aBoard << segment; // draw each segment
311  }
312 
313  } else if (processingName == "FP")
314  {
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 ) );
319  aBoard << theFP;
320 
321  } else if (processingName == "MLP")
322  {
323  typedef FP<std::vector<Z2i::Point>::iterator,int,4> FP;
324  FP theFP( vPts.begin(),vPts.end() );
325 
326  std::vector<FP::RealPoint> v( theFP.size() );
327  theFP.copyMLP( v.begin() );
328 
329  //polyline to draw
330  std::vector<LibBoard::Point> polyline;
331  std::vector<FP::RealPoint>::const_iterator it = v.begin();
332  for ( ;it != v.end();++it)
333  {
334  FP::RealPoint p = (*it);
335  polyline.push_back(LibBoard::Point(p[0],p[1]));
336  }
337  if (isClosed)
338  {
339  FP::RealPoint p = (*v.begin());
340  polyline.push_back(LibBoard::Point(p[0],p[1]));
341  }
342  aBoard.setPenColor(DGtal::Color::Black);
343  aBoard.drawPolyline(polyline);
344 
345  } else if (processingName == "MDCA")
346  {
347  typedef KhalimskySpaceND<2,int> KSpace;
348  typedef GridCurve<KSpace> Curve;
349  Curve curve; //grid curve
350  curve.initFromPointsVector( vPts );
351  typedef Curve::IncidentPointsRange Range; //range
352  Range r = curve.getIncidentPointsRange(); //range
353  typedef Range::ConstCirculator ConstCirculator; //iterator
354  typedef StabbingCircleComputer<ConstCirculator> SegmentComputer; //segment computer
355  //typedef GeometricalDCA<ConstIterator> SegmentComputer; //segment computer
356  typedef SaturatedSegmentation<SegmentComputer> Segmentation;
357  //Segmentation theSegmentation( r.begin(), r.end(), SegmentComputer() );
358  Segmentation theSegmentation( r.c(), r.c(), SegmentComputer() );
359  theSegmentation.setMode("Last");
360  // board << curve;
361  Segmentation::SegmentComputerIterator it = theSegmentation.begin();
362  Segmentation::SegmentComputerIterator itEnd = theSegmentation.end();
363  Board2D otherBoard;
364  otherBoard.setPenColor(DGtal::Color::Black);
365  otherBoard << curve;
366  for ( ; it != itEnd; ++it )
367  {
368  aBoard << SetMode(SegmentComputer().className(), "") << (*it);
369  otherBoard << SetMode(SegmentComputer().className(), "") << (*it);
370  }
371  otherBoard.saveSVG("mdca.svg", Board2D::BoundingBox, 5000 );
372  }
373  }
374 
375  }
376  }
377 
378 
379  if( inputSDFileName != "" || inputSFPFileName != "" )
380  {
381  std::vector<LibBoard::Point> contourPt;
382  if( inputSDFileName != "" )
383  {
384  std::vector< Z2i::Point > contour = PointListReader< Z2i::Point >::getPointsFromFile(inputSDFileName);
385  for(unsigned int j=0; j<contour.size(); j++)
386  {
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);
390  if(pointSize != 0.0)
391  {
392  aBoard.fillCircle(pt.x, pt.y, pointSize);
393  }
394  }
395  }
396 
397  if( inputSFPFileName != "" )
398  {
399  std::vector< PointVector<2,double> > contour =
400  PointListReader< PointVector<2,double> >::getPointsFromFile(inputSFPFileName);
401  for(unsigned int j=0; j<contour.size(); j++)
402  {
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);
406  if(pointSize != 0.0)
407  {
408  aBoard.fillCircle(pt.x, pt.y, pointSize);
409  }
410  }
411  }
412 
413  aBoard.setPenColor(Color::Red);
414  aBoard.setFillColor(Color::Gray);
415  aBoard.setLineStyle (LibBoard::Shape::SolidStyle );
416  aBoard.setLineWidth (lineWidth);
417  if(!fillContour)
418  {
419  aBoard.drawPolyline(contourPt);
420  }else
421  {
422  aBoard.fillPolyline(contourPt);
423  }
424  if( indexPointOpt->count() != 0 )
425  {
426  aBoard.fillCircle((double)(contourPt.at(indexPoint).x), (double)(contourPt.at(indexPoint).y), pointSize);
427  }
428 
429 
430  // display vector field
431  if(displayVectorField != "")
432  {
433  std::vector< PointVector<2,double> > vField;
434  if(optVFAngke->count() != 0)
435  {
436 
437  std::vector<double> vAngles = TableReader<double>::getColumnElementsFromFile(displayVectorField, vectorFromAngle);
438  for(unsigned int i = 0; i < vAngles.size(); i++)
439  {
440  vField.push_back(Z2i::RealPoint(cos(vAngles[i]),sin(vAngles[i])));
441  }
442  }
443  else
444  {
445  vField = PointListReader< PointVector<2,double> >::getPointsFromFile(displayVectorField, vectorFieldIndex);
446  }
447  for(unsigned int i = 0; i< contourPt.size(); i++)
448  {
449  vField[i] = vField[i].getNormalized();
450  auto p = contourPt[i];
451  if(!rotateVectorField)
452  {
453  aBoard.drawArrow(p.x, p.y, p.x+vField[i][0]*scaleVectorField, p.y+vField[i][1]*scaleVectorField );
454  }
455  else
456  {
457  aBoard.drawArrow(p.x, p.y, p.x-vField[i][1]*scaleVectorField, p.y+vField[i][0]*scaleVectorField );
458  }
459  }
460  }
461  }
462 
463 
464 
465 
466  if( outputFileName != "" )
467  {
468  std::string extension = outputFileName.substr(outputFileName.find_last_of(".") + 1);
469  if(extension=="svg")
470  {
471  aBoard.saveSVG(outputFileName.c_str());
472  }
473 #ifdef WITH_CAIRO
474  else
475  if (extension=="eps")
476  {
477  aBoard.saveCairo(outputFileName.c_str(),Board2D::CairoEPS );
478  }
479  else if (extension=="pdf")
480  {
481  aBoard.saveCairo(outputFileName.c_str(),Board2D::CairoPDF );
482  }
483  else if (extension=="png")
484  {
485  aBoard.saveCairo(outputFileName.c_str(),Board2D::CairoPNG );
486  }
487 #endif
488  else if(extension=="eps")
489  {
490  aBoard.saveEPS(outputFileName.c_str());
491  }
492  else if(extension=="fig")
493  {
494  aBoard.saveFIG(outputFileName.c_str(),LibBoard::Board::BoundingBox, 10.0, !noXFIGHeader );
495  }
496  }
497 
498  if (outputStreamSVG)
499  {
500  aBoard.saveSVG(std::cout);
501  }
502  else if (outputStreamFIG)
503  {
504  aBoard.saveFIG(std::cout, LibBoard::Board::BoundingBox, 10.0, !noXFIGHeader);
505  } else if (outputStreamEPS)
506  {
507  aBoard.saveEPS(std::cout);
508  }
509 
510 }
511 
Definition: ATu0v1.h:57