.. default-domain:: cpp .. highlight:: cpp ============================ AIMS developer documentation ============================ For now this document merely contains one or two tips. See also the :pyaims:`PyAims documentation ` and :pyaims:`PyAims tutorial ` for developing exmaples in python language. The current document is dedicated to the C++ API. It may be used conjointly with the Doxygen :aimsdox:`C++ API reference `. .. contents:: index :local: C++ API docs ------------ :aimsdata:`AIMS library C++ API ` AIMS is also composed of several sub-projects: * :cartoddox:`Carto data `: neuroimaging data structures and IO implementations * :aimsdata:`AIMS data `: image processing basics (this doc) * :aimsalgo:`AIMS algo `: algorithms for AIMS * :graphdox:`Graph `: high-level graphs library * :aimsgui:`AIMS GUI `: `Qt-based `_ GUI classes for AIMS * :aimstil:`AIMS Til `: Mainly meshes manipulation tools for AIMS * **Soma-IO**: C++ general IO libraries, containing these sub-projects: * :cartobdox:`Carto base `: C++ general usage library * :somaio:`Soma-IO `: IO libraries (:somaio:`C++ API `) Using graph objects in AIMS --------------------------- Graphs are generic data structures to represent a set of objects (nodes), which may (or may not) be linked by relations. In a general context, nodes and relations are objects which may have various shapes. This definition is general enough to make graphs able to represent almost any kind of objects collections. This is why we use them in AIMS and Anatomist to represent both structured sets of objects, such as sulci graphs, and less structured sets, such as regions of interests (ROI) sets. The practical interest is to have a generic data structure and IO for a wide range of objects sets, with a common representation. We use them to represent many types of neuroimaging objects: ROIs, activation clusters, sulci, gyri, fibers, and more abstract object: sulci recognition and morphometry models, and potentially models of the whole world... In AIMS graphs are represented as :graphdox:`Graph ` objects. This :graphdox:`Graph ` class in C++ may be inherited by more specialized structures in specific applications: in sulci-related algorithms for instance. A graph contains a set of nodes, or vertices, represented in :graphdox:`Vertex ` objects. Relations, or edges, are represented in :graphdox:`Edge `. All ingerit the generic object API, :cartobdox:`GenericObject `, and more precisely the :cartobdox:`PropertySet ` dictionary, which offers both dynamic and builtin properties, and notification capabilities. File formats ++++++++++++ Historically we use the *.arg* format, an ASCII format which stores the graph structure. Alternately AIMS also supports a python/json-like (*.minf*) format, and a XML variant. Lastly we experiment a database representation for single or multiple grpahs in *SQLite3* format (but this has not be generalized in our applications). The graph structure file is generally completed by additional data, which are stored in a *.data* directory. Depending on the nature of the objects contained in the graph nodes and relations, the contents of this directory may vary. It typically stores :aimsdox:`meshes `, voxels lists (:aimsdox:`Buckets `), or :cartoddox:`volumes `. But in specialized frameworks it may contain other objects (models and machine learning objects for sulci model graphs for instance). The *.data* directory has generally two forms for Aims graphical objects: compact ("global") with one file for many objects, or split ("local") with one file per object, which may produce many little files. The current *.arg* format has limitations in its genericity: properties allowed in it must be declared in external syntax files, which have to be loaded (see :cartobdox:`SyntaxReader `). Prerequisite: **cartobase** library basics ++++++++++++++++++++++++++++++++++++++++++ Reference counting !!!!!!!!!!!!!!!!!! Graph objects are based on reference counters. These smart pointers are used just like pointers. :: #include using namespace carto; int main() { rc_ptr rc1( new int ); rc_ptr rc2 = rc1; int a = *rc1 + *rc2; } In short, reference-counting pointers share the ownership of an object and destroy it when nobody needs it any longer: one must never **delete** a reference-counted object, it is done automatically. Generic objects !!!!!!!!!!!!!!! :cartobdox:`GenericObject ` is the base class for all elements in a graph: graph, node, or relation. A common, more specific generic object: *Dictionary*, which is a *typedef* from *std::map*. Another more specialized generic dictionary: :cartobdox:`PropertySet ` which has the same API but supports more interesting featrures. Both support the :cartobdox:`DictionaryInterface ` API. Main generic methods: * :cartobdox:`setProperty ` * :cartobdox:`getProperty ` * iteration on properties, using either the *std::map* iterator, or the :cartobdox:`objectIterator ` method and :cartobdox:`DictionaryIteratorInterface ` API. :cartobdox:`Object ` is a reference counter to a :cartobdox:`GenericObject `. Main classes ++++++++++++ * :graphdox:`Graph ` * :graphdox:`Vertex ` * :graphdox:`Edge ` * :aimsdox:`Reader ` * :aimsdox:`Writer ` * :aimsdox:`RoiIterator ` and inherited classes * :aimsdox:`MaskIterator ` Standard handling +++++++++++++++++ Reading !!!!!!! Avoid using the low-level classes in the :graphdox:`graph library ` (GraphReader / GraphParser / GraphWriter). Instead, use the higher-level AIMS IO: :: #include #include #include using namespace aims; using namespace std; int main( int, char** ) { Reader reader( "filename.arg" ); Graph graph; try { reader.read( graph ); } catch( exception & e ) { cerr << e.what() << endl; } } Iteration on nodes !!!!!!!!!!!!!!!!!! :: Graph::iterator i, e = graph.end(); Vertex *v; for( i=graph.begin(); i!=e; ++i ) { v = *i; // do something with v } Complete example 1 source: .. literalinclude:: ../../code_examples/graphex1.cc :linenos: .. seealso:: the :aimsex:`example 1 ` Iteration on relations !!!!!!!!!!!!!!!!!!!!!! :: Graph::iterator i, e = graph.end(); Vertex::iterator ie, ee; Vertex *v; Edge *edge; for( i=graph.begin(); i!=e; ++i ) { v = *i; for( ie=v->begin(), ee=v->end(); ie!=ee; ++ie ) { edge = *ie; // do something with edge } } .. seealso:: illustrated in :aimsex:`example 1 ` Iteration on ROIs !!!!!!!!!!!!!!!!! This is done using :aimsdox:`RoiIterator ` and :aimsdox:`MaskIteratorOf `, which are "simplified" iterators for ROI graphs which contain :aimsdox:`Buckets `. Currently :aimsdox:`MaskIterator ` does not work on graphs shaped as label volumes. :aimsdox:`RoiIteratorOf ` <:aimsdox:`AimsData ` > however does work on volumes. Complete example 2 source: .. literalinclude:: ../../code_examples/graphex2.cc :linenos: .. seealso:: :aimsex:`example 2 ` source file Access to AIMS objects (meshes, buckets...) in graphs !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Using :aimsdox:`GraphManip ` class and :aimsdox:`GraphElementCode ` structures. * When you know what you are looking for in a graph: .. literalinclude:: ../../code_examples/graphex3.cc :linenos: .. seealso:: :aimsex:`example 3 ` source file * exhaustive iteration: .. literalinclude:: ../../code_examples/graphex4.cc :linenos: .. seealso:: :aimsex:`example 4 ` source file Internal representation: local or global (see files in *.data* directory) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * local: one file per object * global: one file for all objects with the same category identifier, concatenated using the time dimension .. seealso:: illusteated in :aimsex:`example 4 ` Internal / external representation: buckets or volumes !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * Buckets: one bucket per vertex (or relation), with global or local representation * Volumes: one label volume stored in the graph, and an index in each vertex / relation Reading / writing !!!!!!!!!!!!!!!!! The 3rd optional parameter of :aimsdox:`Reader::read ` is used to specify if reading of internal AIMS objects in graphs is requested, and which ones: :: Reader reader( "filename.arg" ); Graph graph; reader.read( graph, 0, -1 ); // read all (vertices + relations) reader.read( graph, 0, 0 ); // read nothing reader.read( graph, 0, 1 ); // read objects in vetices // or with more general reading options (more modern): Reader reader( "filename.arg" ); Graph graph; Object options( new Dictionary ); options->setProperty( "subobjectsfilter", -1 ); // read all, 0: rien, 1: vertices reader.setOptions( options ); reader.read( graph ); Writing: missing objects which were not read are read before the graph is saved back, so that nothing is missing in the written graph. :: #include // ... Writer writer( "filename.arg" ); writer.write( graph ); .. note:: When a graph is re-written in its original directory, but under a different name, it may or may not reuse the same *.data* directory, depending on the *"filename_base"* property in the graph. If this property value is *"\*"*, the *.data* directory will have the same base name as the *.arg*, so will be duplicated. This is the default behaviour in recent AIMS releases. Specialized graphs (sigraph) ++++++++++++++++++++++++++++ These implementations are in the :sidox:`sigraph ` library. * For sulci: :sidox:`FGraph ` * Models: :sidox:`MGraph `, :sidox:`FRGraph `, primal sketches... To read a specialized graph, normally it is sufficient to use the Reader object in "factory" mode (assuming appropriate IO plugins are loaded in AIMS): the specialized graph instance is built and returned by the reader: :: Reader reader( "filename.arg" ); Graph *graph = reader.read(); // graph can be a derived graph, like FGraph or FRGraph. It is also possible to force the graph type and to use the other mode of the Reader: :: Reader reader( "filename.arg" ); FGraph graph; reader.read( graph ); Another specialized use of Graphs: fiber bundles ++++++++++++++++++++++++++++++++++++++++++++++++ Implementation in the :connectdox:`connectomist ` library. The fiber bundles are stored on disk in their own format (*.bundles*, *.bundlesdata*). They have no dedicated data structure in memory: this format has been designed to be read and written on-the-fly, in stream mode (see :connectdox:`BundleProducer `, :connectdox:`BundleListener ` and derived classes). However they can also be read as a graph: this is how they are used in Anatomist. In principle when the connectomist plugin is loaded, :aimsdox:`Reader ` can read *.bundles* files. In bundles graphs nodes, curves or meshes can be found: meshes of segments or triangles. In Python: pyaims ----------------- .. default-domain:: py .. highlight: py .. currentmodule:: soma.aims * The :pyaims:`PyAims documentation is here `. * An example: :pyaims:`in pyaims documentation `. * :class:`~soma.aims.RoiIterator`, :class:`~soma.aims.MaskIterator` and :class:`~soma.aims.GraphManip` are available in Python. Handling in Anatomist --------------------- Load a graph Nomenclatures Viewing meshes / buckets Labels Models, sulci recognition annealing Future evolutions, planed, dreamed, pending... ---------------------------------------------- * ROI / DOI: link between ROIs and data "textures" * Simpler handling of AIMS in graphs, using higher-level layers like RoiIterator / MaskIterator * Complete support of formats XML, minf and SQL * Unification of concepts of graph and .minf * Transparent handling of referentials and transformations * ... ... ... ... .. toctree:: :maxdepth: 1