33 #include <boost/program_options/options_description.hpp>
34 #include <boost/program_options/parsers.hpp>
35 #include <boost/program_options/variables_map.hpp>
41 #include "DGtal/base/Common.h"
42 #include "DGtal/helpers/StdDefs.h"
44 #include "DGtal/shapes/ShapeFactory.h"
45 #include "DGtal/shapes/Shapes.h"
46 #include "DGtal/topology/helpers/Surfaces.h"
49 #include "DGtal/images/imagesSetsUtils/ImageFromSet.h"
50 #include "DGtal/images/imagesSetsUtils/SetFromImage.h"
51 #include "DGtal/images/ImageContainerBySTLVector.h"
52 #include "DGtal/images/ImageSelector.h"
53 #include "DGtal/io/readers/PointListReader.h"
54 #include "DGtal/io/readers/TableReader.h"
55 #include "DGtal/io/Color.h"
57 #include "DGtal/io/readers/GenericReader.h"
61 #include "DGtal/geometry/curves/FreemanChain.h"
64 #include "DGtal/geometry/curves/ArithmeticalDSSComputer.h"
65 #include "DGtal/geometry/curves/GreedySegmentation.h"
66 #include "DGtal/geometry/curves/SaturatedSegmentation.h"
67 #include "DGtal/geometry/curves/FP.h"
68 #include "DGtal/geometry/curves/StabbingCircleComputer.h"
69 #include "DGtal/geometry/curves/SaturatedSegmentation.h"
70 #include "DGtal/geometry/curves/SegmentComputerUtils.h"
72 #include "DGtal/io/boards/Board2D.h"
73 #include "DGtal/io/boards/CDrawableWithBoard2D.h"
75 using namespace DGtal;
174 namespace po = boost::program_options;
177 int main(
int argc,
char** argv )
181 po::options_description general_opt(
"Allowed options are: ");
182 general_opt.add_options()
183 (
"help,h",
"display this message")
184 (
"input,i", po::value<std::string>(),
"input FreemanChain file name")
185 (
"SDP", po::value<std::string>(),
"Import a contour as a Sequence of Discrete Points (SDP format)")
186 (
"SFP", po::value<std::string>(),
"Import a contour as a Sequence of Floating Points (SFP format)")
187 (
"drawContourPoint", po::value<double>(),
"<size> display contour points as disk of radius <size>")
188 (
"fillContour",
"fill the contours with default color (gray)")
189 (
"lineWidth", po::value<double>()->default_value(1.0),
"Define the linewidth of the contour (SDP format)")
190 (
"drawPointOfIndex", po::value<int>(),
"<index> Draw the contour point of index <index> (default 0) ")
191 (
"pointSize", po::value<double>()->default_value(2.0),
"<size> Set the display point size of the point displayed by drawPointofIndex option (default 2.0) ")
192 (
"noXFIGHeader",
" to exclude xfig header in the resulting output stream (no effect with option -outputFile).")
193 (
"withProcessing", po::value<std::string>(),
"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}")
194 (
"outputFile,o", po::value<std::string>(),
" <filename> save output file automatically according the file format extension.")
195 (
"displayVectorField,v", po::value<std::string>(),
"Add the display of a vector field represented by two floating coordinates. Each vector is displayed starting from the corresponding contour point coordinates.")
196 (
"scaleVectorField,v", po::value<double>()->default_value(1.0),
"set the scale of the vector field (default 1) (used with --displayVectorField).")
197 (
"vectorFieldIndex", po::value<std::vector <unsigned int> >()->multitoken(),
"specify the vector field index (by default 0,1) (used with --displayVectorField)." )
198 (
"vectorFromAngle", po::value<unsigned int>(),
"specify that the vectors are defined from an angle value represented at the given index (by default 0) (used with --displayVectorField)." )
199 (
"rotateVectorField",
"apply a CCW rotation of 90° (used with --displayVectorField). ")
200 (
"outputStreamEPS",
" specify eps for output stream format.")
201 (
"outputStreamSVG",
" specify svg for output stream format.")
202 (
"outputStreamFIG",
" specify fig for output stream format.")
203 (
"invertYaxis",
" invertYaxis invert the Y axis for display contours (used only with --SDP)")
205 (
"backgroundImage", po::value<std::string>(),
"backgroundImage <filename> : display image as background ")
206 (
"alphaBG", po::value<double>(),
"alphaBG <value> 0-1.0 to display the background image in transparency (default 1.0), (transparency works only if cairo is available)")
208 (
"scale", po::value<double>(),
"scale <value> 1: normal; >1 : larger ; <1 lower resolutions )");
213 po::variables_map vm;
215 po::store(po::parse_command_line(argc, argv, general_opt), vm);
216 }
catch(
const std::exception& ex){
218 trace.info()<<
"Error checking program options: "<< ex.what()<< std::endl;
222 if(!parseOK||vm.count(
"help")||argc<=1 || (!(vm.count(
"input")) && !(vm.count(
"SDP")) && !(vm.count(
"SFP"))&&
223 !(vm.count(
"backgroundImage")) ) )
225 trace.info()<<
"Display discrete contours. " <<std::endl <<
"Basic usage: "<<std::endl
226 <<
"\t displayContours [options] --input <fileName> "<<std::endl
227 << general_opt <<
"\n";
233 double lineWidth= vm[
"lineWidth"].as<
double>();
234 bool filled = vm.count(
"fillContour");
236 if(vm.count(
"scale")){
237 scale = vm[
"scale"].as<
double>();
241 aBoard.setUnit (0.05*scale, LibBoard::Board::UCentimeter);
248 if(vm.count(
"alphaBG")){
249 alpha = vm[
"alphaBG"].as<
double>();
252 if(vm.count(
"backgroundImage")){
253 std::string imageName = vm[
"backgroundImage"].as<std::string>();
254 typedef ImageSelector<Z2i::Domain, unsigned char>::Type Image;
255 Image img = DGtal::GenericReader<Image>::import( imageName );
256 Z2i::Point ptInf = img.domain().lowerBound();
257 Z2i::Point ptSup = img.domain().upperBound();
258 unsigned int width = abs(ptSup[0]-ptInf[0]+1);
259 unsigned int height = abs(ptSup[1]-ptInf[1]+1);
261 aBoard.drawImage(imageName, 0-0.5,height-0.5, width, height, -1, alpha );
267 if(vm.count(
"input")){
268 std::string fileName = vm[
"input"].as<std::string>();
269 std::vector< FreemanChain<int> > vectFc = PointListReader< Z2i::Point>:: getFreemanChainsFromFile<int> (fileName);
270 aBoard << CustomStyle( vectFc.at(0).className(),
271 new CustomColors( Color::Red , filled? Color::Gray: Color::None ) );
272 aBoard.setLineWidth (lineWidth);
273 for(
unsigned int i=0; i<vectFc.size(); i++){
274 aBoard << vectFc.at(i) ;
275 if(vm.count(
"drawPointOfIndex")){
276 int index = vm[
"drawPointOfIndex"].as<
int>();
277 double size = vm[
"pointSize"].as<
double>();
278 aBoard.setPenColor(Color::Blue);
280 aBoard.fillCircle((
double)(vectFc.at(i).getPoint(index)[0]), (
double)(vectFc.at(i).getPoint(index)[1]), size);
283 if(vm.count(
"withProcessing")){
284 std::string processingName = vm[
"withProcessing"].as<std::string>();
286 std::vector<Z2i::Point> vPts(vectFc.at(i).size()+1);
287 copy ( vectFc.at(i).begin(), vectFc.at(i).end(), vPts.begin() );
289 if ( vPts.at(0) == vPts.at(vPts.size()-1) ) {
292 }
else isClosed =
false;
294 if (processingName ==
"DSS") {
296 typedef ArithmeticalDSSComputer<std::vector<Z2i::Point>::iterator,int,4> DSS4;
297 typedef GreedySegmentation<DSS4> Decomposition4;
300 Decomposition4 theDecomposition( vPts.begin(),vPts.end(),computer );
303 std::string className;
304 for ( Decomposition4::SegmentComputerIterator it = theDecomposition.begin();
305 it != theDecomposition.end(); ++it )
307 DSS4::Primitive segment(it->primitive());
309 aBoard << SetMode( segment.className(),
"BoundingBox" );
310 className = segment.className() +
"/BoundingBox";
311 aBoard << CustomStyle( className,
312 new CustomPenColor( DGtal::Color::Gray ) );
316 }
else if (processingName ==
"MS") {
318 typedef ArithmeticalDSSComputer<std::vector<Z2i::Point>::iterator,int,4> DSS4;
319 typedef SaturatedSegmentation<DSS4> Decomposition4;
323 Decomposition4 theDecomposition( vPts.begin(),vPts.end(),computer );
326 std::string className;
327 for ( Decomposition4::SegmentComputerIterator it = theDecomposition.begin();
328 it != theDecomposition.end(); ++it )
330 DSS4::Primitive segment(it->primitive());
332 aBoard << SetMode( segment.className(),
"BoundingBox" );
333 className = segment.className() +
"/BoundingBox";
334 aBoard << CustomStyle( className,
335 new CustomPenColor( DGtal::Color::Gray ) );
339 }
else if (processingName ==
"FP") {
341 typedef FP<std::vector<Z2i::Point>::iterator,int,4> FP;
342 FP theFP( vPts.begin(),vPts.end() );
343 aBoard << CustomStyle( theFP.className(),
344 new CustomPenColor( DGtal::Color::Black ) );
348 }
else if (processingName ==
"MLP") {
350 typedef FP<std::vector<Z2i::Point>::iterator,int,4> FP;
351 FP theFP( vPts.begin(),vPts.end() );
353 std::vector<FP::RealPoint> v( theFP.size() );
354 theFP.copyMLP( v.begin() );
357 std::vector<LibBoard::Point> polyline;
358 std::vector<FP::RealPoint>::const_iterator it = v.begin();
359 for ( ;it != v.end();++it) {
360 FP::RealPoint p = (*it);
361 polyline.push_back(LibBoard::Point(p[0],p[1]));
364 FP::RealPoint p = (*v.begin());
365 polyline.push_back(LibBoard::Point(p[0],p[1]));
367 aBoard.setPenColor(DGtal::Color::Black);
368 aBoard.drawPolyline(polyline);
370 }
else if (processingName ==
"MDCA") {
371 typedef KhalimskySpaceND<2,int> KSpace;
372 typedef GridCurve<KSpace> Curve;
374 curve.initFromPointsVector( vPts );
375 typedef Curve::IncidentPointsRange Range;
376 Range r = curve.getIncidentPointsRange();
377 typedef Range::ConstCirculator ConstCirculator;
378 typedef StabbingCircleComputer<ConstCirculator> SegmentComputer;
380 typedef SaturatedSegmentation<SegmentComputer> Segmentation;
382 Segmentation theSegmentation( r.c(), r.c(), SegmentComputer() );
383 theSegmentation.setMode(
"Last");
385 Segmentation::SegmentComputerIterator it = theSegmentation.begin();
386 Segmentation::SegmentComputerIterator itEnd = theSegmentation.end();
388 otherBoard.setPenColor(DGtal::Color::Black);
390 for ( ; it != itEnd; ++it ) {
391 aBoard << SetMode(SegmentComputer().className(),
"") << (*it);
392 otherBoard << SetMode(SegmentComputer().className(),
"") << (*it);
394 otherBoard.saveSVG(
"mdca.svg", Board2D::BoundingBox, 5000 );
406 if(vm.count(
"SDP") || vm.count(
"SFP")){
407 bool drawPoints= vm.count(
"drawContourPoint");
408 bool invertYaxis = vm.count(
"invertYaxis");
409 double pointSize=1.0;
411 pointSize = vm[
"drawContourPoint"].as<
double>();
413 std::vector<LibBoard::Point> contourPt;
415 std::string fileName = vm[
"SDP"].as<std::string>();
416 std::vector< Z2i::Point > contour = PointListReader< Z2i::Point >::getPointsFromFile(fileName);
417 for(
unsigned int j=0; j<contour.size(); j++){
418 LibBoard::Point pt((
double)(contour.at(j)[0]),
419 (invertYaxis? (
double)(-contour.at(j)[1]+contour.at(0)[1]):(
double)(contour.at(j)[1])));
420 contourPt.push_back(pt);
422 aBoard.fillCircle(pt.x, pt.y, pointSize);
428 std::string fileName = vm[
"SFP"].as<std::string>();
429 std::vector< PointVector<2,double> > contour =
430 PointListReader< PointVector<2,double> >::getPointsFromFile(fileName);
431 for(
unsigned int j=0; j<contour.size(); j++){
432 LibBoard::Point pt((
double)(contour.at(j)[0]),
433 (invertYaxis? (
double)(-contour.at(j)[1]+contour.at(0)[1]):(
double)(contour.at(j)[1])));
434 contourPt.push_back(pt);
436 aBoard.fillCircle(pt.x, pt.y, pointSize);
443 aBoard.setPenColor(Color::Red);
444 aBoard.setFillColor(Color::Gray);
445 aBoard.setLineStyle (LibBoard::Shape::SolidStyle );
446 aBoard.setLineWidth (lineWidth);
448 aBoard.drawPolyline(contourPt);
450 aBoard.fillPolyline(contourPt);
452 if(vm.count(
"drawPointOfIndex")){
453 int index = vm[
"drawPointOfIndex"].as<
int>();
454 double size = vm[
"pointSize"].as<
double>();
455 aBoard.fillCircle((
double)(contourPt.at(index).x), (
double)(contourPt.at(index).y), size);
460 if(vm.count(
"displayVectorField"))
462 bool rotate = vm.count(
"rotateVectorField");
463 double sv = vm[
"scaleVectorField"].as<
double>();
464 std::vector<unsigned int> vIndex = {0,1};
465 if(vm.count(
"vectorFieldIndex"))
467 vIndex = vm[
"vectorFieldIndex"].as<std::vector<unsigned int>>();
469 std::string vname = vm[
"displayVectorField"].as<std::string>();
470 std::vector< PointVector<2,double> > vField;
471 if(vm.count(
"vectorFromAngle"))
473 unsigned int aIndex = vm[
"vectorFromAngle"].as<
unsigned int>();
474 std::vector<double> vAngles = TableReader<double>::getColumnElementsFromFile(vname, aIndex);
475 for(
unsigned int i = 0; i < vAngles.size(); i++)
477 vField.push_back(Z2i::RealPoint(cos(vAngles[i]),sin(vAngles[i])));
482 vField = PointListReader< PointVector<2,double> >::getPointsFromFile(vname, vIndex);
484 for(
unsigned int i = 0; i< contourPt.size(); i++)
486 vField[i] = vField[i].getNormalized();
487 auto p = contourPt[i];
490 aBoard.drawArrow(p.x, p.y, p.x+vField[i][0]*sv, p.y+vField[i][1]*sv );
494 aBoard.drawArrow(p.x, p.y, p.x-vField[i][1]*sv, p.y+vField[i][0]*sv );
505 if(vm.count(
"outputFile")){
506 std::string outputFileName= vm[
"outputFile"].as<std::string>();
507 std::string extension = outputFileName.substr(outputFileName.find_last_of(
".") + 1);
509 if(extension==
"svg"){
510 aBoard.saveSVG(outputFileName.c_str());
514 if (extension==
"eps"){
515 aBoard.saveCairo(outputFileName.c_str(),Board2D::CairoEPS );
517 if (extension==
"pdf"){
518 aBoard.saveCairo(outputFileName.c_str(),Board2D::CairoPDF );
520 if (extension==
"png"){
521 aBoard.saveCairo(outputFileName.c_str(),Board2D::CairoPNG );
524 else if(extension==
"eps"){
525 aBoard.saveEPS(outputFileName.c_str());
526 }
else if(extension==
"fig"){
527 aBoard.saveFIG(outputFileName.c_str(),LibBoard::Board::BoundingBox, 10.0, !vm.count(
"noXFIGHeader") );
531 if (vm.count(
"outputStreamSVG")){
532 aBoard.saveSVG(std::cout);
534 if (vm.count(
"outputStreamFIG")){
535 aBoard.saveFIG(std::cout, LibBoard::Board::BoundingBox, 10.0, !vm.count(
"noXFIGHeader"));
537 if (vm.count(
"outputStreamEPS")){
538 aBoard.saveEPS(std::cout);