====== Exemple Max-Tree ====== Il est possible d'écrire un programme dédié à la construction d'un arbre en utilisant la bibliothèque Triskele. Voici un exemple tiré des sources {{ :cpp:testmaxtree.cpp |}} Ce programme prend 3 arguments * le nom du fichier contenant l'image en entrée qui construira un arbre MAX * le nom du fichier qui contiendra l'image produite * une liste de valeurs (séparée par des virgules) pour réaliser les élagages Il faut commencer par les déclarations d'usage. La première inclusion sera utilisée pour convertir la liste de paramètre en valeur de seuil pour élagueur l'arbre. Les autres ne sont pas indispensables, car elles seront dans tous les cas incluses par Triskele. // is_any_of #include // pixels type #include "gdal.h" // log functions #include "obelixDebug.hpp" // Point and Size (2D or 3D) #include "obelixGeo.hpp" // read/write images #include "IImage.hpp" // nodata pixels definition in images #include "Border.hpp" De même, on peut déclarer les classes Triskele qui pourront être utilisées. #include "ArrayTree/triskeleArrayTreeBase.hpp" #include "ArrayTree/ArrayTreeBuilder.hpp" #include "Attributes/WeightAttributes.hpp" #include "Attributes/AreaAttributes.hpp" #include "AttributeProfiles.hpp" En fonction de ce qui a été déclaré, il peut être utile de simplifier les appels en omettant le contexte d'utilisation (par exemple en évitant de préfixer avec ''std::''). using namespace std; using namespace boost; using namespace obelix; using namespace obelix::triskele; Dans notre exemple, nous nous limiterons à des images 2D et la construction d'un arbre MAX. static const int GeoDimT (2); static const TreeType treeType = MAX; Nous déclarons la fonction ''filtre'' qui réalisera l'élagage et l'écriture du résultat. Elle sera donc dépendante de la nature des pixels lus ''InPixelT'', de l'image en entrée et de la liste des seuils de coupure. template void filter (const IImage &inputImage, IImage &outputImage, const vector &thresholds); Le point d'entré du programme, commencera par analyser les arguments * argv[0] : nom du programme * argv[1] : nom du fichier contenant l'image en entrée * argv[2] : nom du fichier contenant l'image produite * argv[3] : liste des seuils séparé par des virgules int main (int argc, char** argv, char** envp) { // get parameters if (argc != 4) { cout << "Usage: " << argv[0] << " input-filename outpout-filename thresholds,..." << endl; exit (1); } // set thresholds vetcor vector values; split (values, argv[3], is_any_of (",")); vector thresholds (values.size ()); transform (values.begin (), values.end (), thresholds.begin (), [] (const string &val) { return stoi (val); }); Ensuite nous lisons les métadonnées de l'image pour déterminer la nature des pixels et créer le fichier qui contiendra l'image produite. IImage inputImage (argv[1]); // get metadata inputImage.readImage (); // get image size (width x height) const Size size (inputImage.getSize ()); IImage outputImage (argv[2]); // set metadata outputImage.createImage (size, inputImage.getDataType (), thresholds.size (), inputImage, NullPoint2D); Enfin nous réalisons le traitement en invoquant la fonction ''filtre'' avec le bon type. switch (inputImage.getDataType ()) { case GDT_Byte: filter (inputImage, outputImage, thresholds); break; case GDT_UInt16: filter (inputImage, outputImage, thresholds); break; case GDT_Int16: filter (inputImage, outputImage, thresholds); break; case GDT_UInt32: filter (inputImage, outputImage, thresholds); break; case GDT_Int32: filter (inputImage, outputImage, thresholds); break; case GDT_Float32: filter (inputImage, outputImage, thresholds); break; case GDT_Float64: filter (inputImage, outputImage, thresholds); break; default : cerr << "unknown type!" << endl; break; return 1; } return 0; } Voici la fonction principale du programme. template void filter (const IImage &inputImage, IImage &outputImage, const vector &thresholds) { // switch on debug mode // Log::debug = true; Nous lisons les pixels de l'image. // empty raster Raster raster; // true image size (width x height) const Size size (inputImage.getSize ()); // read first band (0) in 2D mode from origine [0,0] to end [width, height]. inputImage.readBand (raster, 0, NullPoint2D, size); Nous déclarons l'objet arbre qui contiendra le chaînage des feuilles vers la racine. // no border (i.e. all pixels are take in account) const Border border (size, false); // neighbors take in account (default connectivity C4) const GraphWalker graphWalker (border); // tree builder base on raster, connectivity and type of tree ArrayTreeBuilder atb (raster, graphWalker, treeType); // get the number of core const DimCore coreCount (boost::thread::hardware_concurrency ()); // declare empty tree and set the number of thread for all algorithms Tree tree (coreCount); // reserve nodes weight attributes WeightAttributes weightAttributes (tree, getDecrFromTreetype (treeType)); Nous déclenchons la construction de l'arbre. * ATB contient les éléments de l'images (matrice de pixels, connectivité, type d'arbre) * tree coquille vide qui va contenir l'arbre * weightAttributes est le premier tableau d'attributs associés aux nœuds (niveaux de gris) atb.buildTree (tree, weightAttributes); Nous créons un second tableau d'attributs associés aux nœuds (taille en pixels). // create area attribute const AreaAttributes areaAttributes (tree); récupération des cardinalités. // output channels count const DimChannel outputChannelCount (thresholds.size ()); // number of pixels (width x height) const DimImg pixelsCount (size.getPixelsCount ()); Nous produisons des bandes de sorti (élagage de l'arbre) // write node grayscale as attribute profiles AttributeProfiles attributeProfiles (tree); // copy weightAttributes to attributeProfiles atb.setAttributProfiles (attributeProfiles); Nous réalisons toutes les coupures pour tous les seuils définis en arguments du programme. // result allocation memory vector > allBands (outputChannelCount, vector (pixelsCount, 0)); // do all cuts areaAttributes.cut (allBands, attributeProfiles, thresholds); Nous recopions chaque matrice de pixels dans dans le fichier de sorti. // for all cuts for (DimChannel channel (0); channel < outputChannelCount; ++channel) // write output raster outputImage.writeBand (allBands[channel].data (), channel); } ===== Utilisation ===== Si l'on fait l'hypthèse d'être dans le répertoire ''build'' avec la production d'une bibliothèse ''libtriskeledebug.so'' a partir de l'option ''Debug'' de ''cmake'', voici a quoi peut ressembler la commende de compilation : g++ -DNO_OTB -I../triskele/include -I/usr/include/hdf5/serial -I/usr/include/gdal -pthread -g -DENABLE_LOG -std=gnu++11 ../triskele/test/TestMaxTree.cpp -o testMaxTree -L . -ltriskeledebug -lhdf5_serial -lhdf5_serial_cpp -lstdc++ -lpthread -lboost_system -lboost_chrono -lboost_thread -lboost_program_options -lboost_date_time -lboost_serialization -lboost_filesystem -lboost_unit_test_framework -lgdal -ltbb -ltinyxml Sinon, il est possible d'enrichir le fichier ''CMakeLists.txt'' de la manière suivante : message ("sample max tree") add_executable (testMaxTree "test/TestMaxTree.cpp") target_compile_definitions (testMaxTree PUBLIC -DNO_OTB) target_link_libraries (testMaxTree ${allLibs}) Voici un exemple d'utilisation ./testMaxTree strasbourg.tif output.tif 10,100,10000