DGtalTools 2.0.0
Loading...
Searching...
No Matches
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
71using namespace DGtal;
72
73
74
152int 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).");
202 app.add_option("--vectorFieldIndex", vectorFieldIndex ,"specify the vector field index (by default 0,1) (used with --displayVectorField).")
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)");
215 app.add_option("--scale", scale, "scale <value> 1: normal; >1 : larger ; <1 lower resolutions)");
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 DGTAL_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