From a14cb5320117d84fc111b89c50fc305a1ec5b365 Mon Sep 17 00:00:00 2001 From: Edwin Carlinet Date: Tue, 23 Jun 2020 09:01:48 +0200 Subject: [PATCH 1/6] [ci_skip] Work on doc. --- .../concepts/{domains.rst => domains.rst.old} | 0 .../concepts/{indexes.rst => indexes.rst.old} | 0 .../concepts/{points.rst => points.rst.old} | 0 .../concepts/{values.rst => values.rst.old} | 0 .../core/{domains.rst => domains.rst.old} | 0 ...mage_builder.rst => image_builder.rst.old} | 0 .../core/{indexes.rst => indexes.rst.old} | 0 .../core/{pixels.rst => pixels.rst.old} | 0 doc/source/core/{point.rst => point.rst.old} | 0 .../core/{points.rst => points.rst.old} | 0 .../core/{values.rst => values.rst.old} | 0 .../core/values/{rgba.rst => rgba.rst.old} | 0 doc/source/index.rst | 20 +- doc/source/tutorial.rst | 7 +- doc/source/tutorial/component_tree.rst | 411 ------------------ doc/source/tutorial/first_start.rst | 287 +++--------- doc/source/tutorial/installation.rst | 94 ++-- doc/source/tutorial/using_algorithms.rst | 19 + doc/source/tutorial/writing_algorithms.rst | 148 +++++++ 19 files changed, 319 insertions(+), 667 deletions(-) rename doc/source/core/concepts/{domains.rst => domains.rst.old} (100%) rename doc/source/core/concepts/{indexes.rst => indexes.rst.old} (100%) rename doc/source/core/concepts/{points.rst => points.rst.old} (100%) rename doc/source/core/concepts/{values.rst => values.rst.old} (100%) rename doc/source/core/{domains.rst => domains.rst.old} (100%) rename doc/source/core/{image_builder.rst => image_builder.rst.old} (100%) rename doc/source/core/{indexes.rst => indexes.rst.old} (100%) rename doc/source/core/{pixels.rst => pixels.rst.old} (100%) rename doc/source/core/{point.rst => point.rst.old} (100%) rename doc/source/core/{points.rst => points.rst.old} (100%) rename doc/source/core/{values.rst => values.rst.old} (100%) rename doc/source/core/values/{rgba.rst => rgba.rst.old} (100%) delete mode 100644 doc/source/tutorial/component_tree.rst create mode 100644 doc/source/tutorial/using_algorithms.rst create mode 100644 doc/source/tutorial/writing_algorithms.rst diff --git a/doc/source/core/concepts/domains.rst b/doc/source/core/concepts/domains.rst.old similarity index 100% rename from doc/source/core/concepts/domains.rst rename to doc/source/core/concepts/domains.rst.old diff --git a/doc/source/core/concepts/indexes.rst b/doc/source/core/concepts/indexes.rst.old similarity index 100% rename from doc/source/core/concepts/indexes.rst rename to doc/source/core/concepts/indexes.rst.old diff --git a/doc/source/core/concepts/points.rst b/doc/source/core/concepts/points.rst.old similarity index 100% rename from doc/source/core/concepts/points.rst rename to doc/source/core/concepts/points.rst.old diff --git a/doc/source/core/concepts/values.rst b/doc/source/core/concepts/values.rst.old similarity index 100% rename from doc/source/core/concepts/values.rst rename to doc/source/core/concepts/values.rst.old diff --git a/doc/source/core/domains.rst b/doc/source/core/domains.rst.old similarity index 100% rename from doc/source/core/domains.rst rename to doc/source/core/domains.rst.old diff --git a/doc/source/core/image_builder.rst b/doc/source/core/image_builder.rst.old similarity index 100% rename from doc/source/core/image_builder.rst rename to doc/source/core/image_builder.rst.old diff --git a/doc/source/core/indexes.rst b/doc/source/core/indexes.rst.old similarity index 100% rename from doc/source/core/indexes.rst rename to doc/source/core/indexes.rst.old diff --git a/doc/source/core/pixels.rst b/doc/source/core/pixels.rst.old similarity index 100% rename from doc/source/core/pixels.rst rename to doc/source/core/pixels.rst.old diff --git a/doc/source/core/point.rst b/doc/source/core/point.rst.old similarity index 100% rename from doc/source/core/point.rst rename to doc/source/core/point.rst.old diff --git a/doc/source/core/points.rst b/doc/source/core/points.rst.old similarity index 100% rename from doc/source/core/points.rst rename to doc/source/core/points.rst.old diff --git a/doc/source/core/values.rst b/doc/source/core/values.rst.old similarity index 100% rename from doc/source/core/values.rst rename to doc/source/core/values.rst.old diff --git a/doc/source/core/values/rgba.rst b/doc/source/core/values/rgba.rst.old similarity index 100% rename from doc/source/core/values/rgba.rst rename to doc/source/core/values/rgba.rst.old diff --git a/doc/source/index.rst b/doc/source/index.rst index 07bff7d5..4721c71a 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -3,16 +3,28 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to Pylene's documentation! -================================== +Pylene : a modern C++ image processing library +============================================== + +|Pylene| is an open-source image processing library that aims at proving a generic framework to develop IP algorithms +with safety, simplicity and performance in Mind. It is originated from Milena_ with the following objectives: + + +* Simplicity: simple modern C++ syntax with Python binding (in development) +* Efficiency: write algorithms in a simple way and run them as if they were written in C .We follow one guideline: zero-cost abstraction. +* Genericity: write algorithms that are able to run on many kind of images with, yet, zero-cost abstraction. +* Interoperability: run algorithms on image coming from and to external libraries (even on your own image type). + +|Pylene| features ready-to-use image data structures (regular 2D, 3D images) and focus (but is not limited to +Mathematical Morphology Operators). + -Contents: .. toctree:: :maxdepth: 2 Introduction - Quick Start + tutorial Reference Manual Developer Manual diff --git a/doc/source/tutorial.rst b/doc/source/tutorial.rst index a77e58ff..204bd8c1 100644 --- a/doc/source/tutorial.rst +++ b/doc/source/tutorial.rst @@ -1,5 +1,5 @@ -Tutorial -======== +Quick Start +=========== .. |milena| replace:: milena .. |pylene| replace:: pylene @@ -7,7 +7,8 @@ Tutorial .. toctree:: tutorial/installation.rst tutorial/first_start.rst + tutorial/using_algorithms.rst + tutorial/writing_algorithms.rst tutorial/extension.rst tutorial/views.rst - tutorial/component_tree.rst diff --git a/doc/source/tutorial/component_tree.rst b/doc/source/tutorial/component_tree.rst deleted file mode 100644 index 50a2216b..00000000 --- a/doc/source/tutorial/component_tree.rst +++ /dev/null @@ -1,411 +0,0 @@ -Component Trees -=============== - -.. |tos| replace:: Tree of Shapes - -Component trees are morphological hierarchical representations of -images based on their level set decomposition: - -* The min-tree organizes lower connected-components into a tree: - - .. math:: - - \Gamma^- = \{ CC(X) : X \in [u \le \lambda] \} - -* The max-tree organizes upper connected-components into a tree: - - .. math:: - - \Gamma^+ = \{ CC(X) : X \in [u \ge \lambda] \} - -* The |tos| merges the hole-filled components of the min and - max-trees into a single tree. - -.. contents:: - :local: - - - -Computing the tree ------------------- - -The are basically three functions: - -* :cpp:func:`mln::morpho::maxtree` -* :cpp:func:`mln::morpho::mintree` -* :cpp:func:`mln::morpho::tos` - - -.. code:: - - #include - #include - #include - - - mln::image2d f; - mln::io::imread("lena.pgm", f); - auto tree = mln::morpho::maxtree(f, c4); - - -Morphological tree structures ------------------------------ - -A component tree stores only stores the points (or indexes) of the -image (not the values). Components are represented by *nodes* which -only contain the points that are not present in any sub-component. - -* A *tree* `t` provides few features in fact. It allows to retrieve its - set of nodes with ``t.nodes()`` or ``t.nodes_without_root()`` so that - one can iterate on it. Nodes are *ordered*: a forward traversal is top - down (i.e., it goes from the root to the leaves), and a reverse scan - is bottom up. - It also provides a mapping *point or index -> tree node* through the - function ``t.get_node_at``. - -* A *node* `n` is described by a unique *id*, but the function - ``t.nodes()`` does not return a set of *id* but a set of nodes where - a *node* is actually a small structure providing additional - facilities. From a node, one can access to its parent and its - children through ``n.parent()`` or ``n.chidren()``. - -Here are the most important low-level manipulation functions for *trees*: - -* `t` is a tree of type `tree_t` -* `p` is a point or an index from the image -* `id` is a node identifier -* `n` is a node of type `tree_t::node_type` - -+-------------------------------+-------------------------------------------------------------+ -| Function | | -+===============================+=============================================================+ -| ``t.nodes()`` | Return the range of the tree nodes. | -+-------------------------------+-------------------------------------------------------------+ -| ``n = t.get_node_at(p)`` | Return the largest component that contains `p` (its node) | -+-------------------------------+-------------------------------------------------------------+ -| ``n = t.get_node(id)`` | Return a node structure | -+-------------------------------+-------------------------------------------------------------+ -| ``n = t.get_root()`` | Return the root node | -+-------------------------------+-------------------------------------------------------------+ -| ``id = t.get_root_id()`` | Return the root node *identifier* | -+-------------------------------+-------------------------------------------------------------+ -| ``t = t.get_subtree(id)`` | Get the subtree rooted in the node of *identifier* `id`. | -+-------------------------------+-------------------------------------------------------------+ -| ``t.size()`` | Get the size of tree (usually number of nodes) | -+-------------------------------+-------------------------------------------------------------+ - -Here are the most important low-level manipulation functions for -*nodes*: - -+---------------------+-----------------------------------------------------------------+ -| ``n.id()`` | Get the *identifier* of the node. | -+---------------------+-----------------------------------------------------------------+ -| ``n = n.parent()`` | Get the parent node of `n`. | -+---------------------+-----------------------------------------------------------------+ -| ``n.children()`` | Return the range of child nodes of `n`. | -+---------------------+-----------------------------------------------------------------+ -| ``n.is_root()`` | True if the `n` is the root node. | -+---------------------+-----------------------------------------------------------------+ -| ``n.has_child()`` | False if the `n` is a leaf node. | -+---------------------+-----------------------------------------------------------------+ -| ``t = n.tree()`` | Return the underlying tree. | -+---------------------+-----------------------------------------------------------------+ - -Tree traversal examples ------------------------ - -.. topic:: Traversing a branch to get all the components containing `p` - - .. code:: - - tree_t::node_type n = t.get_node_at(p) - while (n.id() != tree_t.npos()) { - // do something with n - n = n.parent(); - } - - -.. topic:: Computing the size of each component. - - .. code:: - - property_map sz(t, 0); // ignore this for now - // Iterate on the image - mln_foreach(auto px, f.pixels()) { - tree_t::node_type n = t.get_node_at(px.index()); - sz[n]++; - } - // Accumulate bottom up - mln_reverse_foreach(auto n, t.nodes_without_root()) { - sz[n.parent()] += sz[n]; - } - -.. topic:: Computing the number of leaves of a node `n` - - .. code:: - - unsigned nleaves = 0; - auto subtree = t.get_subtree(n.id()); - mln_foreach(auto x, subtree.nodes()) - if (not x.has_child()) - nleaves++; - -.. _property map: - -Property maps -------------- - -It is common to associate values to nodes. The implementation keeps a -distinction between the data structure (the *tree*) and the values -associated to the nodes through *property maps*. A property map is a -simple mapping `node -> value` or `node identifier -> value`. -``property_map`` is the type of *property map* for -component trees of type `tree_t` and having property values of type -`V`. - -Here is a example to compute the number of children per node: - -.. code:: - - // Declare and initialize to 0 a property map for the tree - property_map nchildren(t, 0); - - mln_reverse_foreach(auto x, t.nodes_without_root()) - nchilden[x.parent()]++; - - -Attribute maps are versatile and can be computed on the fly (from a -function for example). Below is an example of boolean property map -that says if a node has a single child. It can be used to simplify the -tree by collapsing the nodes in a chain. - -.. code:: - - auto f = [&nchildren](tree_t::node_type x) -> bool { - return nchildren[x] != 1; - }; - auto predicate = make_functional_property_map(f); - - predicate[f.get_root()]; // true or false... - - -Computing attributes --------------------- - -It is really common to compute descriptors on the tree's -components. Such descriptors are generally called *attributes*. They -are computed through :concept:`accumulators `. The result -of the accumulation is stored in a :ref:`property map `. - -Since this is such a common operation, it is already implemented -through a set of algorithms. - -Here: - -* `acc` is an accumulator or a feature. -* `pmap` is a property map - -+--------------------------------------+--------------------------------------------------------------------+ -| ``pmap = accumulate(t,acc)`` | Accumulate the point or indexes of the components (depending if the| -| | tree stores points or indexes). | -+--------------------------------------+--------------------------------------------------------------------+ -| ``pmap = vaccumulate(t, f, acc)`` | Accumulate the values of the `f` pixels foreach component. | -+--------------------------------------+--------------------------------------------------------------------+ -| ``pmap = paccumulate(t, f, acc)`` | Accumulate the points of the `f` pixels foreach component. | -+--------------------------------------+--------------------------------------------------------------------+ -| ``pmap = pixaccumulate(t, f, acc)`` | Accumulate `f` pixels foreach components | -+--------------------------------------+--------------------------------------------------------------------+ - -Each algorithm has a variation denoted with the suffix `*_proper` -(`accumulate_proper`, `vaccumulate_proper` ...) where the -accumulation is done on the proper pixels of each node (i.e., the -pixels that are not in any sub-component). - -Below is an example for computing the average gray level of each component. - -.. code:: - - #include - #include - - image2d f = ...; - tree_t f = ...; - auto gl_map = morpho::accumulate(t, f, accu::features::mean<> ()); - - -Property maps are also used to encode the original values of the image -from which the tree has been built. This is done thanks to the -function `make_property_map_from_image`:: - - property_map vmap = make_attribute_map_from_image(t, f); - - - -Filtering the tree ------------------- - -Filtering is also a common operation on morphological trees. There -exist several filtering strategies: *min, max, and direct*, -implemented through the algorithms below: - -`pred` is a boolean *property map* where `pred[x] = true` says that we -want to preserve the node `x`. - -+--------------------------------------+-----------------------------------------------+ -| ``filter_min_inplace(t, pred)`` | Min filtering strategy | -+--------------------------------------+-----------------------------------------------+ -| ``filter_max_inplace(t, pred)`` | Max filtering strategy | -+--------------------------------------+-----------------------------------------------+ -| ``filter_direct_inplace(t, pred)`` | Direct filtering strategy | -+--------------------------------------+-----------------------------------------------+ - -Here is an example of filtering to collapse the nodes part of a chain -to simplify the tree:: - - #include ... // as above - #include - - auto f = [&nchildren](tree_t::node_type x) -> bool { - return nchildren[x] != 1; - }; - auto predicate = make_functional_property_map(f); - filter_direct_inplace(t, predicate); - -Image reconstruction --------------------- - -The next step after image filtering is generally the reconstruction of -the image from the filtered tree. This is done through the algorithm -`reconstruction`:: - - #include - - tree_t filtered_tree = ...; // the filtered tree - property_map vmap = ...; // the property map: node -> value - - image2d out; - resize(out, f); - reconstruction(filtered_tree, vmap, out); - - -Loading and saving a tree -------------------------- - -There are basically two IO routines for component trees -`mln::morpho::load` and `mln::morpho::save` illustrated below:: - - #include - - tree_t t = ...; // The tree - - std::ofstream outfile("mytree"); - morpho::save(t, outfile); - - tree_t t2; - std::ifstream infile("mytree"); - morpho::load(infile, t2); - - -A complete example ------------------- - -Filtering the square roadsigns. - -.. image:: /snippets/images/roadsigns.png - -Method description -^^^^^^^^^^^^^^^^^^ - -The method will proceed as follows: - -1. Compute the |tos| of the input image:: - - auto t = mln::morpho::tos(f); - -2. The |tos| uses a special representation that needs to double the - size of the image by adding intermediate pixels. We thus need to - resize the input image (leaving the values on intermediate pixels - undefined) for further processing:: - - mln::image2d f2; - mln::resize(f2, t._get_data()->m_pmap); - mln::box2d d = f2.domain(); - mln::copy(f, f2 | mln::sbox2d{d.pmin, d.pmax, {2,2}}); - -3. Compute the bounding box of each shape and its size. Note - that the bbox is actually the `inf` and `sup` of the points in the - shape:: - - auto prop_map = mln::morpho::paccumulate(t, f2, - mln::accu::features::inf<> () & - mln::accu::features::sup<> () & - mln::accu::features::count<> ()); -4. Filter the objects that: - - * are not too big (< 1000 x 1000 pixels) - * are not too small (> 100 x 100 pixels) - * cover 95% of the bounding box at least (so rectangular shapes) - - :: - - auto pred = [&prop_map](tree_t::vertex_id_t x) { - mln::point2d pmin = mln::accu::extractor::inf(prop_map[x]); - mln::point2d pmax = mln::accu::extractor::sup(prop_map[x]); - unsigned sz = mln::accu::extractor::count(prop_map[x]); - unsigned area_bbox = (pmax[0] - pmin[0] + 1) * (pmax[1] - pmin[1] + 1); - return sz > (0.95 * area_bbox) and sz > 10000 and sz < 1000000; - }; - auto pred_ = mln::make_functional_property_map(pred); - mln::morpho::filter_direct_inplace(t, pred_); - -5. Reconstruct the image:: - - mln::image2d out; - mln::resize(out, t._get_data()->m_pmap); - - auto vmap = mln::morpho::make_attribute_map_from_image(t, f2); - mln::morpho::reconstruction(t, vmap, out); - -(The full code is given below) - -It gives the following result: - -.. image:: /snippets/images/roadsigns-square.png - - -Which is not bad but not perfect. Roadsigns have a high contrast -between their background and their content, thus a large variance. We -can use this to improve the classification. The minimal variance was -arbitrary set to 250, which means an average of at least 50 gray -levels with average gray level of the shape:: - - auto var_map = mln::morpho::vaccumulate(t, f2, mln::accu::features::variance<> ()); - - auto pred = [&prop_map,&var_map](tree_t::vertex_id_t x) { - mln::point2d pmin = mln::accu::extractor::inf(prop_map[x]); - mln::point2d pmax = mln::accu::extractor::sup(prop_map[x]); - unsigned sz = mln::accu::extractor::count(prop_map[x]); - unsigned area_bbox = (pmax[0] - pmin[0] + 1) * (pmax[1] - pmin[1] + 1); - double var = var_map[x]; - return sz > (0.95 * area_bbox) and sz > 10000 and sz < 1000000 and var > 250; - }; - -Result: - -.. image:: /snippets/images/roadsigns-square-2.png - - -Full code -^^^^^^^^^ - -.. literalinclude:: /snippets/component_tree_1.cpp - - - - - - - - - - diff --git a/doc/source/tutorial/first_start.rst b/doc/source/tutorial/first_start.rst index 869ad7a2..64653867 100644 --- a/doc/source/tutorial/first_start.rst +++ b/doc/source/tutorial/first_start.rst @@ -1,260 +1,109 @@ -First steps in the library -========================== +Creating and loading images +=========================== -Objectives: - -* provide image types and basic manipulation routines -* provide a framework for easy-to-write and efficient image processing algorithms - -Image representation in Pylene +Regular 2D images from scratch ------------------------------ -An :cpp:concept:`Image` is basically a function associating a *point* to a -*value*. The pair *(point,value)* is called a :cpp:concept:`Pixel`. The *domain* of -an image is the *ordered range* of points for which the function is -defined. - -* Example of *point* type: - ``mln::point2d``, ``mln::point3d``... -* Example of *domain* types: - ``mln::box2d``, ``std::set`` -* Example of *value* types: - ``uint8_t``, ``double``, ``mln::rgb8`` -* Example of *image* types: - ``mln::image2d``, ``mln::image3d`` - - - +:cpp:any:`mln::image2d\` is the most-used image type representing images defined on a 2D grid. It is a template +class, where the parameter `T` can be replaced by the type of value to store. For instance, if it is a grayscale image +with values encoded on 8-bits unisgned integers, `T` will be `uint8_t`. For RGB-8 images, `T` is ``mln::rgb8``. Any +*regular* (foundamental) type can be used, fixed-size scalar and floating-point types are already defined in C++ in +the ` `_ header. The template parameter `T` is that we call +the *value type* (every image has a *value type*, be it static or dynamic) -Creating/Loading/Saving an image --------------------------------- - -Creating an image from scratch -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:cpp:class:`mln::image2d` is the most-used image type representing images -defined on a 2D grid. It can be creating from a set of values. For -instance, in the following code, a 2 × 3 2D image is created with -values from 1 to 6:: +An image might be created from a set of values (this is generally used only for testing an algorithm). For instance, in +the following code, a 2 × 3 2D image is created with values from 1 to 6:: #include - mln::image2d f = {{1,2,3}, {4,5,6}}; - -A 2D image can also be created from its width and height:: - - mln::image2d f(2,3); - -Finally a 2D image domain may not start at `(0,0)`. One can initialize -an image from its domain and also provide an initial value for its -elements (and also a border, we will see later):: + mln::image2d f = {{1,2,3}, {4,5,6}}; - mln::box2d d = {{1,1}, {5,5}}; - mln::image2d f(d); // A 4 x 4 image starting at (1,1) with a default border - mln::image2d g(d, 0); // A 4 x 4 image starting at (1,1) with no border - mln::image2d h(d, 0, 3); // A 4 x 4 image starting at (1,1) with no border initialized with value 3 +It is generally more commom to create a 2D image from its size, using its width and its height to reserve space. Note +that values are (generally) undefined:: + // Create a 800x600 2D images + mln::image2d f(800, 600); -Loading an image -^^^^^^^^^^^^^^^^ +A last parameter allows to customize the initialization of an image. It can be used to initialize an image with a custom +value, e.g. the grayscale value 128:: -An image can be loaded from a file. It actually relies on the -`freeimage `_ library to -handle most file formats:: + // Create a 800x600 2D images + mln::image2d f(800, 600, {.init_value = uint8_t(128)}) - #include - #include - mln::image2d f; - mln::io::imread("input.pgm", f); -Saving an image -^^^^^^^^^^^^^^^ +Finally a 2D image may not start at location `(0,0)`. For instance when want to work a sub-regions of an image, the +location of the origin has moved. Every image is a tied to a *domain*, which is a :cpp:class:`box2d` for 2D images. +One can initialize an image from a domain of a pair *(width, height)*:: -An image can be saved to a file. Yet it relies on the `freeimage -`_. The file format is -automatically deduced from the filename extension when it is -possible:: + // A roi (x=50,y=50,w=100,h=100) + mln::box2d roi = {{50,50}, {150,150}}; + mln::image2d f(roi); - #include - #include +Regular ND images +----------------- - mln::image2d f = { {1,2,3}, {4,5,6} }; - mln::io::imsave(f, "out.pgm"); +The class :cpp:class:`image2d` is generalized in any dimension (:cpp:class:`image1d`, :cpp:class:`image3d` and +so on). Actually, they are aliases over the type (:cpp:class:`__ndbuffer_image` where the dimension is fixed). - -Displaying an image -^^^^^^^^^^^^^^^^^^^ - -To display an image on the console, use :cpp:func:`mln::io::imprint`:: +Thus you can create 3D-images from a initializer-lists:: #include - #include - - mln::image2d f = { {1,2,3}, {4,5,6} }; - mln::io::imprint(f); - - -It should display. -.. code-block:: none + // A 2x2x3 3D-image + mln::image2d f = { + {{1,2,3}, {4,5,6}}, + {{7,8,9}, {10,11,12}} + }; - [[0,0] ... [2,3]](h) - 1 2 3 - 4 5 6 +From a triplet (width,height,depth):: -Traversing and accessing image values -------------------------------------- - -Accessing image values -^^^^^^^^^^^^^^^^^^^^^^ - -Most standard image types (see :concept:`Accessible Image`) supports -accessing a value though its point:: - - mln::image2d f = { {1,2,3}, {4,5,6} }; - mln::point2d p = {1,1}; - std::cout << f(p) << "\n"; // Affiche 5 - -Note that indexes are in the order `(row, col)`. `(0,0)` refers to the -topleft corner and `(1,2)` to the bottom-right corner. + // Create a 800x600 2D images + mln::image2d f(128, 128, 128); -For 2D image, an equivalent writing is with :cpp:func:`image2d::at_`:: - - mln::image2d f = { {1,2,3}, {4,5,6} }; - std::cout << f.at_(1,1) << "\n"; // Affiche 5 - -.. note:: +From a :cpp:class:`box3d` domain:: - There are some first differences with Milena_: + // A roi (x=50,y=50,z=50,w=100,h=100,d=100) + mln::box2d roi = {{50,50,50}, {150,150,150}}; + mln::image3d f(roi); - * First the range for the domain in Milena_ is closed, - (i.e. `domain = [pmin,pmax]`), here it is half-open to follow the - usual convention of the C++ standard library, so it is `domain = - [pmin,pmax)` and `pmax` is not included in the range. - * Second, every image ``f`` in Milena_ supports ``f(p)`` where - ``p`` is point of the domain. This is not always the case with - this library as we provide more flexible ways to iterate on images. +Loading and saving an image +--------------------------- -Traversing images -^^^^^^^^^^^^^^^^^ - -Most images (more precisely :concept:`Forward Image`) provide 3 ways -of traversing. - -* Iterating on *points* through the *domain* -* Iterating on *values* -* Iterating on *pixels* - -As a consequence, such an image ``f`` provide: - -* ``f.domain()`` The range of the image *points* -* ``f.values()`` The range of the image *values* -* ``f.pixels()`` The range of the image *pixels* - -An image can be birectional (see :concept:`Bidirectional Image`) and -allows to be traversed in the reverse order. In that case, the -*ranges* are bidirectional as well. Below is an example of image traversal. - -.. literalinclude:: /snippets/first_start_1.cpp - -It produces the following output. - -.. code-block:: none - - == Traversing forward == - Traversing through points. - [0,0]:1 - [0,1]:2 - [0,2]:3 - [1,0]:4 - [1,1]:5 - [1,2]:6 - Traversing on values. - 1 - 2 - 3 - 4 - 5 - 6 - Traversing with pixels. - [0,0]:1 - [0,1]:2 - [0,2]:3 - [1,0]:4 - [1,1]:5 - [1,2]:6 - - == Traversing backward == - Traversing through points. - [1,2]:6 - [1,1]:5 - [1,0]:4 - [0,2]:3 - [0,1]:2 - [0,0]:1 - Traversing on values. - 6 - 5 - 4 - 3 - 2 - 1 - Traversing with pixels. - [1,2]:6 - [1,1]:5 - [1,0]:4 - [0,2]:3 - [0,1]:2 - [0,0]:1 - -.. note:: - - Contrary to Milena_, the ordering of the traversal of images is - defined. Domains are *ordered* ranges. This means there is a - **total order** on *point* type. In the case of - :cpp:class:`mln::point2d`, this is the lexicographical order - (i.e., the natural scan order of 2D grids). Traversing with *value* - or *pixel* range follows the same order. - - -Traversing with ranges and iterators -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The underlying concepts behind multidimensional ranges. They are like -normal C++ ranges but have a different interface to enable faster traversal. This is why, you -cannot use a normal `for` on these ranges but ``mln_foreach``. - - - mln_foreach(auto px, f.pixels()) - std::cout << px.point() << " : ' << px.val() << "\n"; - -.. note:: +An image can be loaded from a file. It actually relies on the +`freeimage `_ library to +handle most file formats:: - Contrary to Milena_ with do not provide *proxy iterators* as it is - more common to directly iterate with ``mln_foreach`` on values. + #include + #include + { + mln::image2d f; + mln::io::imread("input.pgm", f); + } + { + mln::image2d f = { {1,2,3}, {4,5,6} }; + mln::io::imsave(f, "out.pgm"); + } -Traversing several images in the same time -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Images from existing data +------------------------- -Image and range views enable to pack (zip) several objects in a single object:: - - auto vals_1 = f.values(); - auto vals_2 = g.values(); - mln_foreach((auto [v1, v2]), mln::ranges::view::zip(vals_1, vals_2)) - ... +In your application, would will mostly want to use algorithms from many libraries that do not share the image types. As +soon as an image is encoded as C raw-buffer of data, you will be able to exchange images from/to pylene using +:cpp:func:`mln::__ndbuffer_image::from_buffer`. -You can also iterate using a domain is the image supports direct access by points:: - - mln_foreach(auto p, domain) - // Use f(p) and f(g) +:: + uint8_t data[] = {255, 0, 0, 255}; + int dims[] = {2, 2}; + auto input = mln::image2d::from_buffer(data, dims); +And you can access the Pylene internal buffer with :cpp:func:`buffer ` diff --git a/doc/source/tutorial/installation.rst b/doc/source/tutorial/installation.rst index d53ee791..48b4f5c0 100644 --- a/doc/source/tutorial/installation.rst +++ b/doc/source/tutorial/installation.rst @@ -1,5 +1,5 @@ Installation -############ +============ .. contents:: :local: @@ -13,22 +13,25 @@ particular: * `Boost `_ * `Range-v3 `_ +It also depends on *FreeImage* which can be installted with your package manager on most distribution. The packages are +generally named `freeimage` and `freeimage-devel`. + + There are three ways to install the C++ Pylene: * The preferred and strongly recommended way to use Pylene is using Conan, a C++ package manager that would handle the dependencies. * The other way is using installing the libraries from sources. +.. highlight:: shell -Install (for users) -=================== Install from sources -******************** +-------------------- To build from sources, you will need cmake and install all the dependencies. Conan can be used to install the dependencies. -Download the latest release from FIXME. +Download the latest release from `Pylene Gitlab `_ 1. Untar the archive:: @@ -39,32 +42,38 @@ Download the latest release from FIXME. mkdir build && cd build conan install .. -#. Build the library:: +#. Build the library (with no test):: - cmake .. -DCMAKE_BUILD_TYPE=release - cmake --build . --target Pylene + cmake .. -DCMAKE_BUILD_TYPE=release -DPYLENE_BUILD_LIBS_ONLY=On + cmake --build . --target Pylene (or make) #. Install the library (as root):: - cmake --build . --target install + cmake --build . --target install (or make install) + +.. tip:: + + You can install in a specific local as *normal* user in your home directory. To install in $HOME/.local + use:: + + cmake . -DCMAKE_INSTALL_PREFIX=$HOME/.local + cmake --build . --target install Integration with CMake and Conan (preferred) -******************************************** +-------------------------------------------- `Conan `_ is a C++ package manager that can be installed with pip. The Pylene library is available on our repository https://artifactory.lrde.epita.fr/ -1. Add the repository in your conan remotes: +1. Add the repository in your conan remotes:: - .. code-block:: shell - - conan remote add lrde-public https://artifactory.lrde.epita.fr/artifactory/api/conan/lrde-public + conan remote add lrde-public https://artifactory.lrde.epita.fr/artifactory/api/conan/lrde-public 2. In a :file:`conanfile.txt`, add the reference to Pylene:: - pylene/head@lrde/stable + pylene/head@lrde/stable Then, see conan's documentation for how to use the package with your favorite build system. The following steps apply to CMake. @@ -72,18 +81,19 @@ Then, see conan's documentation for how to use the package with your favorite bu 4. In your :file:`CMakeLists.txt`, use **find_package** as usual:: - find_package(Pylene) + set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR} ${CMAKE_MODULE_PATH}) + find_package(Pylene) The following targets are then available: -* ``Pylene::Pylene``: target to link with when using Pylene. Ex:: +* ``Pylene::Pylene``: target to link with when using Pylene:: target_link_libraries(MyTarget PRIVATE Pylene::Pylene) Integration with CMake as a subdirectory -**************************************** +---------------------------------------- You can add the :file:`pylene` library directory into your project and include it in your :file:`CMakeLists.txt` file:: @@ -96,29 +106,29 @@ or to exclude it from ``make``, ``make all``, or ``cmake --build ..``:: The following targets are then available: -* ``Pylene::Pylene``: target to link with when using Pylene. Ex:: +* ``Pylene::Pylene``: target to link with when using Pylene:: target_link_libraries(MyTarget PRIVATE Pylene::Pylene) Integration with CMake from an existing installation -**************************************************** +---------------------------------------------------- The library installs CMake config files and provide CMake targets. Use ``find_package`` in your CMakeLists:: - find_package(Pylene CONFIG) + find_package(Pylene) It makes the following targets available: -* ``Pylene::Pylene``: target to link with when using Pylene. Ex:: +* ``Pylene::Pylene``: target to link with when using Pylene:: target_link_libraries(MyTarget PRIVATE Pylene::Pylene) -Install (for developers) -======================== +Installation (for developers) +----------------------------- #. Clone the repository:: @@ -141,19 +151,43 @@ Install (for developers) benchmark:shared = True gtest:shared = True - In the source directory, use: + In the source directory, use:: + + mkdir build && cd build + conan install .. + cmake .. + cmake --build . + + +Sample project structure using Pylene +------------------------------------- + +See `https://gitlab.lrde.epita.fr/olena/pylene/-/blob/master/test_package/`_. + + +* :file:`conanfile.txt`:: + + [requires] + pylene/head@lrde/stable + + +* :file:`CMakeLists.txt`:: - .. code-block:: shell - mkdir build && cd build - conan install .. - cmake .. - cmake --build . + project(PyleneTest) + set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR} ${CMAKE_MODULE_PATH}) + find_package(Pylene REQUIRED) + add_executable(main main.cpp) + target_link_libraries(main Pylene::Pylene) +* Build intructions:: + mkdir build && cd build + conan install .. -g cmake_find_package + cmake .. diff --git a/doc/source/tutorial/using_algorithms.rst b/doc/source/tutorial/using_algorithms.rst new file mode 100644 index 00000000..ce8cdfed --- /dev/null +++ b/doc/source/tutorial/using_algorithms.rst @@ -0,0 +1,19 @@ +Using algorithms +================ + + +Using the library is straighforward. Many ready-to-use algorithm just takes images as input and returns an +image. Consider the algorithm :cpp:func:`mln::morpho::dilation`. In its simplest form, this algorithm +takes an image, a structuring element and returns an image, ``dilation(in, se) -> out`:: + + #include + #include input; + mln::io::imread("input.tiff", input); + + auto output = mln::morpho::dilation(input, mln::se::disc(5)); + mln::io::imsave(output, "out.tiff"); + + + diff --git a/doc/source/tutorial/writing_algorithms.rst b/doc/source/tutorial/writing_algorithms.rst new file mode 100644 index 00000000..9e3ecb46 --- /dev/null +++ b/doc/source/tutorial/writing_algorithms.rst @@ -0,0 +1,148 @@ +Traversing and accessing image values +------------------------------------- + +Accessing image values +^^^^^^^^^^^^^^^^^^^^^^ + +Most standard image types (see :concept:`Accessible Image`) supports +accessing a value though its point:: + + mln::image2d f = { {1,2,3}, {4,5,6} }; + mln::point2d p = {1,1}; + std::cout << f(p) << "\n"; // Affiche 5 + +Note that indexes are in the order `(row, col)`. `(0,0)` refers to the +topleft corner and `(1,2)` to the bottom-right corner. + +For 2D image, an equivalent writing is with :cpp:func:`image2d::at_`:: + + mln::image2d f = { {1,2,3}, {4,5,6} }; + std::cout << f.at_(1,1) << "\n"; // Affiche 5 + +.. note:: + + There are some first differences with Milena_: + + * First the range for the domain in Milena_ is closed, + (i.e. `domain = [pmin,pmax]`), here it is half-open to follow the + usual convention of the C++ standard library, so it is `domain = + [pmin,pmax)` and `pmax` is not included in the range. + + * Second, every image ``f`` in Milena_ supports ``f(p)`` where + ``p`` is point of the domain. This is not always the case with + this library as we provide more flexible ways to iterate on images. + +Traversing images +^^^^^^^^^^^^^^^^^ + +Most images (more precisely :concept:`Forward Image`) provide 3 ways +of traversing. + +* Iterating on *points* through the *domain* +* Iterating on *values* +* Iterating on *pixels* + +As a consequence, such an image ``f`` provide: + +* ``f.domain()`` The range of the image *points* +* ``f.values()`` The range of the image *values* +* ``f.pixels()`` The range of the image *pixels* + +An image can be birectional (see :concept:`Bidirectional Image`) and +allows to be traversed in the reverse order. In that case, the +*ranges* are bidirectional as well. Below is an example of image traversal. + +.. literalinclude:: /snippets/first_start_1.cpp + +It produces the following output. + +.. code-block:: none + + == Traversing forward == + Traversing through points. + [0,0]:1 + [0,1]:2 + [0,2]:3 + [1,0]:4 + [1,1]:5 + [1,2]:6 + Traversing on values. + 1 + 2 + 3 + 4 + 5 + 6 + Traversing with pixels. + [0,0]:1 + [0,1]:2 + [0,2]:3 + [1,0]:4 + [1,1]:5 + [1,2]:6 + + == Traversing backward == + Traversing through points. + [1,2]:6 + [1,1]:5 + [1,0]:4 + [0,2]:3 + [0,1]:2 + [0,0]:1 + Traversing on values. + 6 + 5 + 4 + 3 + 2 + 1 + Traversing with pixels. + [1,2]:6 + [1,1]:5 + [1,0]:4 + [0,2]:3 + [0,1]:2 + [0,0]:1 + +.. note:: + + Contrary to Milena_, the ordering of the traversal of images is + defined. Domains are *ordered* ranges. This means there is a + **total order** on *point* type. In the case of + :cpp:class:`mln::point2d`, this is the lexicographical order + (i.e., the natural scan order of 2D grids). Traversing with *value* + or *pixel* range follows the same order. + + +Traversing with ranges and iterators +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The underlying concepts behind multidimensional ranges. They are like +normal C++ ranges but have a different interface to enable faster traversal. This is why, you +cannot use a normal `for` on these ranges but ``mln_foreach``. + + + mln_foreach(auto px, f.pixels()) + std::cout << px.point() << " : ' << px.val() << "\n"; + +.. note:: + + Contrary to Milena_ with do not provide *proxy iterators* as it is + more common to directly iterate with ``mln_foreach`` on values. + + + +Traversing several images in the same time +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Image and range views enable to pack (zip) several objects in a single object:: + + auto vals_1 = f.values(); + auto vals_2 = g.values(); + mln_foreach((auto [v1, v2]), mln::ranges::view::zip(vals_1, vals_2)) + ... + +You can also iterate using a domain is the image supports direct access by points:: + + mln_foreach(auto p, domain) + // Use f(p) and f(g) -- GitLab From 93c438fcd1d02ea190a621b5f242e0003fb191ae Mon Sep 17 00:00:00 2001 From: Edwin Carlinet Date: Tue, 23 Jun 2020 09:02:16 +0200 Subject: [PATCH 2/6] Remove cpp-20 from conanfile. --- conanfile.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/conanfile.py b/conanfile.py index 34598491..6be5d657 100644 --- a/conanfile.py +++ b/conanfile.py @@ -25,17 +25,19 @@ class Pylene(ConanFile): build_requires = [ "gtest/[>=1.10]", "benchmark/[>=1.5.0]", + + # For now boost is too heavy and is not based on components + # Such a dependancy brings linktime overhead because too many libraries are linked + # "boost/1.73.0" ] requires = [ "range-v3/0.10.0", "fmt/6.0.0", - "boost/1.73.0" ] def configure(self): - self.settings.compiler.cppstd = "20" tools.check_min_cppstd(self, "20") def build(self): @@ -54,6 +56,8 @@ class Pylene(ConanFile): self.cpp_info.names["cmake_find_package"] = "Pylene" self.cpp_info.names["cmake_find_package_multi"] = "Pylene" self.cpp_info.libs = [ "Pylene" ] + + self.cpp_info.cxxflags.append(tools.cppstd_flag(self.settings)) -- GitLab From a9ae9e9549c4e7037f49ad80f30d4912ab93f76f Mon Sep 17 00:00:00 2001 From: Edwin Carlinet Date: Thu, 9 Jul 2020 15:01:14 +0200 Subject: [PATCH 3/6] Work on documentation. --- LICENSE | 376 +++++++++++++++++- doc/source/conf.py | 2 +- doc/source/core.rst | 21 +- doc/source/core/algorithm/accumulate.rst | 8 +- doc/source/core/algorithm/all_any_none_of.rst | 8 +- doc/source/core/algorithm/clone.rst | 3 +- doc/source/core/algorithm/count_if.rst | 4 +- doc/source/core/algorithm/equal.rst | 4 +- doc/source/core/algorithm/foreach.rst | 2 +- doc/source/core/algorithm/transform.rst | 4 +- doc/source/core/core_types.rst | 14 + ...mage_builder.rst.old => image_builder.rst} | 0 doc/source/core/images.rst | 40 +- doc/source/core/images/ndimage.rst | 189 ++++----- doc/source/core/{point.rst.old => point.rst} | 17 +- doc/source/core/view/operators.rst | 14 +- doc/source/core/view/transform.rst | 2 +- doc/source/labeling/cdt.rst | 2 + doc/source/morpho.rst | 2 +- doc/source/morpho/area_filter.rst | 4 +- doc/source/morpho/closing.rst | 4 +- doc/source/morpho/dilation.rst | 4 +- doc/source/morpho/dynamic_filter.rst | 4 +- doc/source/morpho/erosion.rst | 5 +- doc/source/morpho/extinction_transform.rst | 4 +- doc/source/morpho/fill_hole.rst | 2 +- doc/source/morpho/gradient.rst | 6 +- doc/source/morpho/hit_or_miss.rst | 2 +- doc/source/morpho/median_filter.rst | 6 +- doc/source/morpho/opening.rst | 4 +- .../morpho/opening_by_reconstruction.rst | 20 +- doc/source/morpho/rank_filter.rst | 8 +- doc/source/morpho/tos.rst | 2 +- doc/source/ruminations/neighborhood.rst | 11 +- doc/source/tutorial.rst | 1 - doc/source/tutorial/first_start.rst | 21 +- doc/source/tutorial/installation.rst | 21 +- doc/source/tutorial/using_algorithms.rst | 28 +- doc/source/tutorial/writing_algorithms.rst | 272 +++++++------ pylene/include/mln/core/image/ndimage_fwd.hpp | 4 + 40 files changed, 819 insertions(+), 326 deletions(-) create mode 100644 doc/source/core/core_types.rst rename doc/source/core/{image_builder.rst.old => image_builder.rst} (100%) rename doc/source/core/{point.rst.old => point.rst} (91%) diff --git a/LICENSE b/LICENSE index 41dc2327..a612ad98 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,373 @@ -This Source Code Form is subject to the terms of the Mozilla Public -License, v. 2.0. If a copy of the MPL was not distributed with this -file, You can obtain one at http://mozilla.org/MPL/2.0/. +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/doc/source/conf.py b/doc/source/conf.py index 9e82f8d5..2c2bf41c 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -46,7 +46,7 @@ master_doc = 'index' # General information about the project. project = u'Pylene' -copyright = u'2018, LRDE' +copyright = u'2020, LRDE' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/doc/source/core.rst b/doc/source/core.rst index a9e2f833..a754feb3 100644 --- a/doc/source/core.rst +++ b/doc/source/core.rst @@ -1,13 +1,13 @@ Core Module =========== - +.. cpp:namespace:: mln .. toctree:: :hidden: - + core/core_types core/images core/ranges core/neighborhood @@ -52,19 +52,22 @@ See :doc:`core/images` for a description of the image concepts and image basics. + + .. topic:: Fundamental image types .. table:: :class: full :widths: auto - +--------------+-------------------------+ - | `image2d` | Buffer-encoded 2D image | - +--------------+-------------------------+ - | `image3d` | Buffer-encoded 3D image | - +--------------+-------------------------+ - | `ndimage` | Buffer-encoded nD image | - +--------------+-------------------------+ + +-----------------------------------------+-------------------------+ + | :cpp:any:`image2d` | Buffer-encoded 2D image | + +-----------------------------------------+-------------------------+ + | :cpp:any:`image3d` | Buffer-encoded 3D image | + +-----------------------------------------+-------------------------+ + | :cpp:any:`ndimage` | Buffer-encoded nD image | + +-----------------------------------------+-------------------------+ + .. topic:: Functional image views diff --git a/doc/source/core/algorithm/accumulate.rst b/doc/source/core/algorithm/accumulate.rst index f4cbdbc9..daa4dc08 100644 --- a/doc/source/core/algorithm/accumulate.rst +++ b/doc/source/core/algorithm/accumulate.rst @@ -5,8 +5,7 @@ Include :file:`` .. cpp:namespace:: mln -#. .. cpp:function:: template V accumulate(InputImage in, V init, BinaryFunction op) - +#. .. cpp:function:: template V accumulate(InputImage in, V init, BinaryFunction op) #. .. cpp:function:: template auto accumulate(InputImage in, Accumulator accu) @@ -57,10 +56,9 @@ Examples mln::image2d ima = { {1, 2, 3}, {4, 5, 6} }; int s = mln::accumulate(ima, mln::accu::features::sum<>()); - - + Complexity ---------- Linear in the number of pixels. - \ No newline at end of file + diff --git a/doc/source/core/algorithm/all_any_none_of.rst b/doc/source/core/algorithm/all_any_none_of.rst index 2e8656d7..0a552a2d 100644 --- a/doc/source/core/algorithm/all_any_none_of.rst +++ b/doc/source/core/algorithm/all_any_none_of.rst @@ -7,15 +7,15 @@ All_of, any_of, none_of .. cpp:namespace:: mln -#. .. cpp:function:: bool all_of(InputImage ima, UnaryPredicate p) +#. .. cpp:function:: bool all_of(InputImage ima, std::UnaryPredicate p) #. .. cpp:function:: bool all_of(InputImage ima) -#. .. cpp:function:: bool any_of(InputImage ima, UnaryPredicate p) +#. .. cpp:function:: bool any_of(InputImage ima, std::UnaryPredicate p) #. .. cpp:function:: bool any_of(InputImage ima) -#. .. cpp:function:: bool none_of(InputImage ima, UnaryPredicate p) +#. .. cpp:function:: bool none_of(InputImage ima, std::UnaryPredicate p) #. .. cpp:function:: bool none_of(InputImage ima) @@ -26,7 +26,7 @@ All_of, any_of, none_of :param ima: The image to test :param p: The unary predicate that will be applied on values :tparam InputImage: A model of :cpp:concept:`InputImage` - :tparam UnaryPredicate: A model of :cpp:concept:`stl::UnaryPredicate` + :tparam std::UnaryPredicate: A model of :cpp:concept:`std::UnaryPredicate` :return: True or false diff --git a/doc/source/core/algorithm/clone.rst b/doc/source/core/algorithm/clone.rst index 46aa7418..3d84948d 100644 --- a/doc/source/core/algorithm/clone.rst +++ b/doc/source/core/algorithm/clone.rst @@ -5,7 +5,7 @@ Include :file:`` .. cpp:namespace:: mln -.. cpp:function:: image_concrete_t clone(InputImage src) +.. cpp:function:: InputImage{I} image_concrete_t clone(I src) Clone the values from the source image `src` to a destination image which is automatically deduced as the concrete type of the input. This primitive is directed at: @@ -25,7 +25,6 @@ Include :file:`` :tparam OutputImage: A model of :cpp:concept:`OutputImage` :return: The concrete image of `src` with the same values - Examples -------- diff --git a/doc/source/core/algorithm/count_if.rst b/doc/source/core/algorithm/count_if.rst index 47b24dcd..c2ee45db 100644 --- a/doc/source/core/algorithm/count_if.rst +++ b/doc/source/core/algorithm/count_if.rst @@ -5,14 +5,14 @@ Include :file:`` .. cpp:namespace:: mln -.. cpp:function:: std::ptrdiff_t count_if(InputImage ima, UnaryPredicate p) +.. cpp:function:: std::ptrdiff_t count_if(InputImage ima, std::UnaryPredicate p) Count the number of pixel whose value verify the predicate `p` in `ima`. :param ima: The image to be trasversed :param p: The predicate to verify :tparam InputImage: A model of :cpp:concept:`InputImage` - :tparam UnaryPredicate: A model of :cpp:concept:`stl::UnaryPredicate` + :tparam std::UnaryPredicate: A model of :cpp:concept:`std::UnaryPredicate` :return: number of pixels whose value verifies `p` in `ima` diff --git a/doc/source/core/algorithm/equal.rst b/doc/source/core/algorithm/equal.rst index 1190de30..a440dcd8 100644 --- a/doc/source/core/algorithm/equal.rst +++ b/doc/source/core/algorithm/equal.rst @@ -5,7 +5,7 @@ Include :file:`` .. cpp:namespace:: mln -.. cpp:function:: bool equal(LhsImage lhs, RhsImage rhs) +.. cpp:function:: Image{A} Image{B} bool equal(A lhs, B rhs) Compare the pixels of `lhs` and `rhs`. The result is true if and only if rhs's values equal lhs's values. @@ -32,4 +32,4 @@ Complexity ---------- Linear in the number of pixels. - \ No newline at end of file + diff --git a/doc/source/core/algorithm/foreach.rst b/doc/source/core/algorithm/foreach.rst index 76c1cc6b..d3cc364b 100644 --- a/doc/source/core/algorithm/foreach.rst +++ b/doc/source/core/algorithm/foreach.rst @@ -5,7 +5,7 @@ Include :file:`` .. cpp:namespace:: mln -.. cpp:function:: void for_each(InputImage in, UnaryFunction f) +.. cpp:function:: void for_each(InputImage in, std::UnaryFunction f) Applies the function `f` to every value of `in`. It can be used for in-place transformation. diff --git a/doc/source/core/algorithm/transform.rst b/doc/source/core/algorithm/transform.rst index 0213a39e..e9439cea 100644 --- a/doc/source/core/algorithm/transform.rst +++ b/doc/source/core/algorithm/transform.rst @@ -5,9 +5,9 @@ Include :file:`` .. cpp:namespace:: mln -#. .. cpp:function:: void transform(InputImage in, OutputImage out, UnaryFunction f) +#. .. cpp:function:: void transform(InputImage in, OutputImage out, std::UnaryFunction f) -#. .. cpp:function:: image_ch_value_t transform(InputImage in, UnaryFunction f) +#. .. cpp:function:: image_ch_value_t transform(InputImage in, std::UnaryFunction f) 1) Applies the function `f` to every value of `in` and stores the result in `out`. diff --git a/doc/source/core/core_types.rst b/doc/source/core/core_types.rst new file mode 100644 index 00000000..af051578 --- /dev/null +++ b/doc/source/core/core_types.rst @@ -0,0 +1,14 @@ +Core Types +========== + + + +Enumerated types +---------------- + + +.. doxygenenum:: sample_type_id + + + + diff --git a/doc/source/core/image_builder.rst.old b/doc/source/core/image_builder.rst similarity index 100% rename from doc/source/core/image_builder.rst.old rename to doc/source/core/image_builder.rst diff --git a/doc/source/core/images.rst b/doc/source/core/images.rst index 3acae7f3..a7c2d5e5 100644 --- a/doc/source/core/images.rst +++ b/doc/source/core/images.rst @@ -10,6 +10,7 @@ Forsee to add pdim (point) and vdim (value) for dimension constant in iamge conc .. contents:: :local: +.. cpp:namespace:: mln Description & Design Overview ============================= @@ -231,11 +232,14 @@ Image Concepts Image-related Concepts ^^^^^^^^^^^^^^^^^^^^^^ +Concepts are defined in the namespace :cpp:expr:`mln::concepts`. + In the introduction, we have seen that an image *f* is function associating **points** to **values**. **Values** are simple :cpp:concept:`std::Regular` types. **Points** are also :cpp:concept:`std::Regular` but are also :cpp:concept:`StrictTotallyOrdered` because they are the basis of *domains*. -.. cpp:namespace:: mln::concepts + +.. cpp:namespace:: mln .. cpp:concept:: template Domain A *domain* is a :cpp:concept:`std::Range` of *points* which is totally ordered (this ensures a traversal order of @@ -330,9 +334,9 @@ The figure below illustrates image properties and some of the image concept. Image Concept ^^^^^^^^^^^^^ -#. .. cpp:concept:: template Image -#. .. cpp:concept:: template InputImage -#. .. cpp:concept:: template ForwardImage +#. .. cpp:concept:: template Image +#. .. cpp:concept:: template InputImage +#. .. cpp:concept:: template ForwardImage **Image** (also **ForwardImage** and **InputImage**) is the minimal concept for modeling images. It provides *read* @@ -611,6 +615,34 @@ Indexable Image Concept | ``cima.delta_index(dp)`` | `index_type` | | Get the index difference for a shift of *dp* | +----------------------------+--------------+--------------+----------------------------------------------------+ +Image Traits +============ + +.. cpp:namespace:: mln + +.. cpp:type:: template image_concrete_t = I::concrete_type + template image_ch_value_t = I::ch_value_type + + Get the concrete of an image (a type that is writable and can be resized). In the second, it requests an + image whose value type is `V`. + +.. cpp:type:: template image_value_t = I::value_type + template image_reference_t = I::reference + + Get the type of the values of an image. *Value type* is the naked type, *reference* is the type returned + by the expression `ima(p)` which is generally `T&`. + +.. cpp:type:: template image_domain_t = I::domain_type + template image_point_t = I::point_type + + Get the type of the domain and the type of the points (*points* being the domain values) + + +.. cpp:type:: template image_index_t = I::index_type + + Get the type of the index of :cpp:concept:`Indexable` images. + + Image Views =========== diff --git a/doc/source/core/images/ndimage.rst b/doc/source/core/images/ndimage.rst index afc59007..9727ee99 100644 --- a/doc/source/core/images/ndimage.rst +++ b/doc/source/core/images/ndimage.rst @@ -12,7 +12,7 @@ Include: .. cpp:namespace:: mln -N-dimensional buffer images :cpp:class:`__ndbuffer_image` +N-dimensional buffer images :cpp:class:`__ndbuffer_image` are the most common image types that stores elements within a buffer. Memory layout and memory management @@ -32,24 +32,27 @@ the last reference goes out. While the type of the element `T` and the number of dimension `pdim` are known at compile-time, :cpp:class:`__ndbuffer_image` supports partial type and dimension erasure. -+------+--------------+---------------------------+------------------------+ -| T | pdim | Type alias | Description | -+======+==============+===========================+========================+ -| void | dynamic = -1 | :cpp:any:`ndbuffer_image` | Full type-erased image | -+------+--------------+---------------------------+------------------------+ -| T | 1 | :cpp:any:`image1d\` | 1d image type | -+------+--------------+---------------------------+------------------------+ -| T | 2 | :cpp:any:`image2d\` | 2d image type | -+------+--------------+---------------------------+------------------------+ -| T | 3 | :cpp:any:`image3d\` | 3d image type | -+------+--------------+---------------------------+------------------------+ -| T | N | :cpp:any:`ndimage\` | nd image type | -+------+--------------+---------------------------+------------------------+ + + ++------+--------------+-----------------------------------------+----------------------+ +| T | pdim | Type alias | Description | ++======+==============+=========================================+======================+ +| void | dynamic = -1 | :cpp:any:``ndbuffer_image`` | Full type-erased | ++------+--------------+-----------------------------------------+----------------------+ +| T | 1 | :cpp:any:``image1d\ `` | 1d image type | ++------+--------------+-----------------------------------------+----------------------+ +| T | 2 | :cpp:any:``image2d\ `` | 2d image type | ++------+--------------+-----------------------------------------+----------------------+ +| T | 3 | :cpp:any:``image3d\ `` | 3d image type | ++------+--------------+-----------------------------------------+----------------------+ +| T | N | :cpp:any:``ndimage\ `` | nd image type | ++------+--------------+-----------------------------------------+----------------------+ .. cpp:type:: ndbuffer_image = __ndbuffer_image -.. cpp:type:: template image1d = __ndbuffer_image -.. cpp:type:: template image2d = __ndbuffer_image -.. cpp:type:: template image3d = __ndbuffer_image +.. cpp:type:: template image1d = __ndbuffer_image +.. cpp:type:: template image2d = __ndbuffer_image +.. cpp:type:: template image3d = __ndbuffer_image +.. cpp:type:: template ndimage = __ndbuffer_image Border management ***************** @@ -68,18 +71,18 @@ Overview of the n-dimensional image API :stub-columns: 1 :class: table-synopsis - * - + * - - ``__ndbuffer_image`` - ``__ndbuffer_image`` * - Constructors - .. cpp:alias:: __ndbuffer_image::__ndbuffer_image - - .. cpp:alias:: template __ndbuffer_image::__ndbuffer_image + - .. cpp:alias:: template __ndbuffer_image::__ndbuffer_image * - Constructors from external sources - .. cpp:alias:: __ndbuffer_image::from_buffer - - .. cpp:alias:: template __ndbuffer_image::from_buffer + - .. cpp:alias:: template __ndbuffer_image::from_buffer * - Resizing - .. cpp:alias:: __ndbuffer_image::resize - - .. cpp:alias:: template __ndbuffer_image::resize + - .. cpp:alias:: template __ndbuffer_image::resize * - Geometry information - .. cpp:alias:: __ndbuffer_image::pdim __ndbuffer_image::width @@ -88,13 +91,13 @@ Overview of the n-dimensional image API __ndbuffer_image::size __ndbuffer_image::border __ndbuffer_image::domain - - .. cpp:alias:: template __ndbuffer_image::pdim - template __ndbuffer_image::width - template __ndbuffer_image::height - template __ndbuffer_image::depth - template __ndbuffer_image::size - template __ndbuffer_image::border - template __ndbuffer_image::domain + - .. cpp:alias:: template __ndbuffer_image::pdim + template __ndbuffer_image::width + template __ndbuffer_image::height + template __ndbuffer_image::depth + template __ndbuffer_image::size + template __ndbuffer_image::border + template __ndbuffer_image::domain * - Data & Layout information - .. cpp:alias:: __ndbuffer_image::sample_type @@ -103,35 +106,35 @@ Overview of the n-dimensional image API __ndbuffer_image::stride __ndbuffer_image::index_of_point __ndbuffer_image::point_at_index - __ndbuffer_image::delta_index - - .. cpp:alias:: template __ndbuffer_image::sample_type - template __ndbuffer_image::buffer - template __ndbuffer_image::byte_stride - template __ndbuffer_image::stride - template __ndbuffer_image::index_of_point - template __ndbuffer_image::point_at_index - template __ndbuffer_image::delta_index + __ndbuffer_image::delta_index + - .. cpp:alias:: template __ndbuffer_image::sample_type + template __ndbuffer_image::buffer + template __ndbuffer_image::byte_stride + template __ndbuffer_image::stride + template __ndbuffer_image::index_of_point + template __ndbuffer_image::point_at_index + template __ndbuffer_image::delta_index * - Data accessors - .. cpp:alias:: __ndbuffer_image::operator() __ndbuffer_image::at __ndbuffer_image::operator[] - - .. cpp:alias:: template __ndbuffer_image::operator() - template __ndbuffer_image::at - template __ndbuffer_image::operator[] + - .. cpp:alias:: template __ndbuffer_image::operator() + template __ndbuffer_image::at + template __ndbuffer_image::operator[] * - Slicing & clipping operations - .. cpp:alias:: __ndbuffer_image::clip __ndbuffer_image::row - __ndbuffer_image::slice - - .. cpp:alias:: template __ndbuffer_image::clip - template __ndbuffer_image::row - template __ndbuffer_image::slice + __ndbuffer_image::slice + - .. cpp:alias:: template __ndbuffer_image::clip + template __ndbuffer_image::row + template __ndbuffer_image::slice * - Casting operators - .. cpp:alias:: __ndbuffer_image::cast_to - Implicitely convertible to :cpp:any:`ndbuffer_image` * - Iteration facilities - - - .. cpp:alias:: template __ndbuffer_image::values() - template __ndbuffer_image::pixels() + - .. cpp:alias:: template __ndbuffer_image::values() + template __ndbuffer_image::pixels() API Reference of the dynamic N-dimensional buffer images (`ndbuffer_image`) @@ -143,7 +146,7 @@ API Reference of the dynamic N-dimensional buffer images (`ndbuffer_image`) .. cpp:type:: point_type = Point value_type = void* - index_type = int + index_type = int domain_type = Box @@ -207,26 +210,26 @@ API Reference of the dynamic N-dimensional buffer images (`ndbuffer_image`) __ndbuffer_image(sample_type_id sample_type, int width, const image_build_params& params = {}) __ndbuffer_image(sample_type_id sample_type, int width, int height, const image_build_params& params = {}) __ndbuffer_image(sample_type_id sample_type, int width, int height, int depth, const image_build_params& params = {}) - + Creates an image of dimensions given by `domain` with the given `sample_type`. The overloads are provided for convenience: - + 2. Creates a 1d image of the given `width` 3. Creates a 2d image of size `width × height` 4. Creates a 3d image of size `width × height × depth` By default, the memory is left default-initialized. The optional `params` parameter can be used to provide advanced initialization information: - + * `params.init_value` can be used to value-initialize the buffer - * `params.border` can be used to allocate the image with a given border size. + * `params.border` can be used to allocate the image with a given border size. .. code-block:: // Create a 3d image of size (width=2, height=3, depth=4) with type uint8_t and default border width (3) // and random values ndbuffer_image a(sample_type_id::UINT8, 2, 3, 4); - + // Create a 2d image of size (width=5, height=5) with type uint16_t and border width = 5px // with values set to zero. @@ -240,7 +243,7 @@ API Reference of the dynamic N-dimensional buffer images (`ndbuffer_image`) .. cpp:function:: __ndbuffer_image(const __ndbuffer_image& other, const image_build_params&) - Initialization constructor + Initialization constructor .. cpp:function:: template __ndbuffer_image(std::initializer_list) @@ -257,9 +260,9 @@ API Reference of the dynamic N-dimensional buffer images (`ndbuffer_image`) .. rubric:: Construction from external buffers - .. cpp:function:: static ndbuffer_image from_buffer(std::byte* buffer, sample_type_id sample_type, int dim, const\ - int sizes[], const std::ptrdiff_t byte_strides[] = nullptr, bool copy = false) - static ndbuffer_image from_buffer(std::byte* buffer, sample_type_id sample_type, int dim, const\ + .. cpp:function:: static ndbuffer_image from_buffer(std::byte* buffer, sample_type_id sample_type, int dim, const \ + int sizes[], const std::ptrdiff_t byte_strides[] = nullptr, bool copy = false) + static ndbuffer_image from_buffer(std::byte* buffer, sample_type_id sample_type, int dim, const \ int topleft[], const int sizes[], const std::ptrdiff_t byte_strides[] = nullptr, bool copy = false) Constructs an image using an external buffer. @@ -284,7 +287,7 @@ API Reference of the dynamic N-dimensional buffer images (`ndbuffer_image`) void resize(sample_type_id sample_type, ConstBoxRef domain, const image_build_params& = {}) See the corresponding contructors. These functions allow an image to be default-constructed and resized afterward. - + .. note:: A new buffer is allocated. If a buffer was already attached to the image and this is the last reference, the memory is reclaimed. @@ -301,7 +304,7 @@ API Reference of the dynamic N-dimensional buffer images (`ndbuffer_image`) .. cpp:function:: int height() const noexcept - Get the height of the image (0 if empty). Returns 1 if the image is 1D. + Get the height of the image (0 if empty). Returns 1 if the image is 1D. .. cpp:function:: int depth() const noexcept @@ -325,7 +328,7 @@ API Reference of the dynamic N-dimensional buffer images (`ndbuffer_image`) .. cpp:function:: sample_type_id sample_type() const noexcept Get the sample type of the data. - + .. cpp:function:: std::byte* buffer() const noexcept Get a pointer to first element (in the domain). @@ -341,7 +344,7 @@ API Reference of the dynamic N-dimensional buffer images (`ndbuffer_image`) .. cpp:function:: index_type index_of_point(ConstPointRef p) const noexcept Get the linear index (offset in the buffer) of multi-dimensional point. - + .. cpp:function:: point_type point_at_index(index_type i) const noexcept Get the point corresponding to the given index. @@ -360,14 +363,14 @@ API Reference of the dynamic N-dimensional buffer images (`ndbuffer_image`) :except: std::runtime_error if `y` in invalid or `dim() != 3`. .. cpp:function:: ndbuffer_image row(int y) const - + Return the row at coordinate `y` in the 2nd dimension. :except: std::runtime_error if `y` in invalid or `dim() != 2`. - + .. cpp:function:: ndbuffer_image clip(ConstBoxRef roi) const - Return the image restricted to the ROI `roi`. `roi` must be included in the domain. + Return the image restricted to the ROI `roi`. `roi` must be included in the domain. :except: std::runtime_error if ``domain().includes(roi)`` is false or dimensions mismatch. @@ -376,21 +379,21 @@ API Reference of the dynamic N-dimensional buffer images (`ndbuffer_image`) .. cpp:function:: const void* operator() (ConstPointRef p) const noexcept void* operator() (ConstPointRef p) noexcept - + Returns a pointer to the element at `p`. - + **Precondition**: ``this->domain().has(p)`` .. cpp:function:: const void* at (ConstPointRef p) const noexcept void* at (ConstPointRef p) noexcept - + Returns a pointer to the element at `p`. `p` can be in the extension. - + **Precondition**: `p` belongs to the extended domain. .. cpp:function:: const void* operator[] (index_type i) const noexcept void* operator[] (index_type i) noexcept - + Returns a pointer to the element at index `i`. **Precondition**: `i` must be a valid index. @@ -399,9 +402,9 @@ API Reference of the dynamic N-dimensional buffer images (`ndbuffer_image`) .. rubric:: Casting operators .. cpp:function:: template \ - const __ndbuffer_image* cast_to() const + const __ndbuffer_image* cast_to() const template \ - __ndbuffer_image* cast_to() + __ndbuffer_image* cast_to() Down-cast (or trans-cast) to the requested n-dimensional image type. Returns `nullptr` if the requested types do not match the dynamic type information. @@ -418,7 +421,7 @@ API Reference of the dynamic N-dimensional buffer images (`ndbuffer_image`) API Reference of the static N-dimensional buffer images (`ndimage`) ************************************************************************* -.. cpp:class:: template __ndbuffer_image +.. cpp:class:: template __ndbuffer_image .. rubric:: Type definitions @@ -427,7 +430,7 @@ API Reference of the static N-dimensional buffer images (`ndimage`) index_type = int domain_type = ndbox pixel_type - const_pixel_type + const_pixel_type .. rubric:: Constructors @@ -492,29 +495,29 @@ API Reference of the static N-dimensional buffer images (`ndimage`) .. cpp:function:: __ndbuffer_image(ndbox domain, const image_build_params& = {}) [[when N = 1]] __ndbuffer_image(int width, const image_build_params& params = {}) - [[when N = 2]] __ndbuffer_image(int width, int height, const image_build_params& params = {}) + [[when N = 2]] __ndbuffer_image(int width, int height, const image_build_params& params = {}) [[when N = 3]] __ndbuffer_image(int width, int height, int depth, const image_build_params& params = {}) - + Creates an image of dimensions given by `domain` with value type given by ``T``. The overloads are provided for convenience and availability depends on ``N``: - + 2. **When N = 1** Creates a 1d image of the given `width` 3. **When N = 2** Creates a 2d image of size `width × height` 4. **When N = 3** Creates a 3d image of size `width × height × depth` By default, the memory is left default-initialized. The optional `params` parameter can be used to provide advanced initialization information: - + * `params.init_value` can be used to value-initialize the buffer - * `params.border` can be used to allocate the image with a given border size. + * `params.border` can be used to allocate the image with a given border size. .. code-block:: // Create a 3d image of size (width=2, height=3, depth=4) with type uint8_t and default border width (3) // and random values image3d a(2, 3, 4); - + // Create a 2d image of size (width=5, height=5) with type uint16_t and border width = 5px // with values set to zero. @@ -525,7 +528,7 @@ API Reference of the static N-dimensional buffer images (`ndimage`) .. cpp:function:: __ndbuffer_image(const __ndbuffer_image& other, const image_build_params&) - Initialization constructor + Initialization constructor .. cpp:function:: [[when N = 1]] __ndbuffer_image(std::initializer_list) @@ -544,7 +547,7 @@ API Reference of the static N-dimensional buffer images (`ndimage`) .. rubric:: Construction from external buffers - .. cpp:function:: static ndbuffer_image from_buffer(T* buffer, const int sizes[], const std::ptrdiff_t byte_strides[] = nullptr, bool copy = false) + .. cpp:function:: static ndbuffer_image from_buffer(T* buffer, const int sizes[], const std::ptrdiff_t byte_strides[] = nullptr, bool copy = false) static ndbuffer_image from_buffer(T* buffer, const int topleft[], const int sizes[], const std::ptrdiff_t byte_strides[] = nullptr, bool copy = false) Constructs an image using an external buffer. @@ -567,7 +570,7 @@ API Reference of the static N-dimensional buffer images (`ndimage`) void resize(ConstBoxRef domain, const image_build_params& = {}) See the corresponding contructors. These functions allow an image to be default-constructed and resized afterward. - + .. note:: A new buffer is allocated. If a buffer was already attached to the image and this is the last reference, the memory is reclaimed. @@ -585,7 +588,7 @@ API Reference of the static N-dimensional buffer images (`ndimage`) .. cpp:function:: int height() const noexcept - Get the height of the image. Returns 1 if the image is 1D. + Get the height of the image. Returns 1 if the image is 1D. .. cpp:function:: int depth() const noexcept @@ -609,7 +612,7 @@ API Reference of the static N-dimensional buffer images (`ndimage`) .. cpp:function:: sample_type_id sample_type() const noexcept Get the sample type of the data. - + .. cpp:function:: T* buffer() const noexcept Get a pointer to first element (in the domain). @@ -625,7 +628,7 @@ API Reference of the static N-dimensional buffer images (`ndimage`) .. cpp:function:: index_type index_of_point(ndpoint p) const noexcept Get the linear index (offset in the buffer) of multi-dimensional point. - + .. cpp:function:: ndpoint point_at_index(index_type i) const noexcept Get the point corresponding to the given index. @@ -645,14 +648,14 @@ API Reference of the static N-dimensional buffer images (`ndimage`) **exceptions**: std::runtime_error if `z` is invalid .. cpp:function:: [[when N = 2]] image1d row(int y) const noexcept - + Return the row at coordinate `y` in the 2nd dimension. **exceptions**: std::runtime_error if `y` is invalid - - .. cpp:function:: __ndbuffer_image clip(ndbox roi) const - Return the image restricted to the ROI `roi`. `roi` must be included in the domain. + .. cpp:function:: __ndbuffer_image clip(ndbox roi) const + + Return the image restricted to the ROI `roi`. `roi` must be included in the domain. :except: std::runtime_error if ``domain().includes(roi)`` is false or dimensions mismatch. @@ -661,21 +664,21 @@ API Reference of the static N-dimensional buffer images (`ndimage`) .. cpp:function:: const T& operator() (ndpoint p) const noexcept T& operator() (ndpoint p) noexcept - + Returns a reference to the element at `p`. - + **Precondition**: ``this->domain().has(p)`` .. cpp:function:: const T& at (ndpoint p) const noexcept T& at (ndpoint p) noexcept - + Returns a reference to the element at `p`. `p` can be in the extension. - + **Precondition**: `p` belongs to the extended domain. .. cpp:function:: const T& operator[] (index_type i) const noexcept T& operator[] (index_type i) noexcept - + Returns a reference to the element at index `i`. **Precondition**: `i` must be a valid index. @@ -684,7 +687,7 @@ API Reference of the static N-dimensional buffer images (`ndimage`) .. cpp:function:: auto values() const auto values() - + Returns a range to iterate on image values. .. cpp:function:: auto pixels() const diff --git a/doc/source/core/point.rst.old b/doc/source/core/point.rst similarity index 91% rename from doc/source/core/point.rst.old rename to doc/source/core/point.rst index e101e93e..39ee9cd5 100644 --- a/doc/source/core/point.rst.old +++ b/doc/source/core/point.rst @@ -23,25 +23,24 @@ Class hierarchy diagrams for ndpoints. They all implement the :cpp:class:`__Poin Default constructor. - .. cpp:function:: ndpoint(const P& other) + .. cpp:function:: template ndpoint(const P& other) + + Converting constructor from any point implementing the :cpp:class:`__PointInterface`. This overload is enabled + only if `P` is compatible with ``ndpoint`` i.e. if ``P::value_type`` is convertible to ``T`` and ``ndim == (-1 + || other.ndim)``. - Converting constructor from any point implementing the :cpp:class:`__PointInterface`. This overload is enabled only if `P` is compatible with ``ndpoint`` i.e. if ``P::value_type`` is convertible to ``T`` and - ``ndim == (-1 || other.ndim)``. - .. cpp:function:: ndpoint(int dim) Construction with the number of dimensions given dynamically. Only available when ``ndim == -1``. - - .. cpp:class:: template ndpointref `ndpointref` represents a n-dimensional points (coordinates) over a grid. The number of dimensions can be known at compile time or dynamic ``ndim = -1``. It has a reference semantic and should be used as a function parameter only. - 1. .. cpp:function:: ndpointref(P& other) - 2. .. cpp:function:: ndpointref(const P& other) + 1. .. cpp:function:: template ndpointref(P& other) + 2. .. cpp:function:: template ndpointref(const P& other) Converting constructor from any point implementing the :cpp:class:`__PointInterface`. This overload is enabled only if `P` is compatible with ``ndpointref``, i.e. if ``P::value_type*`` is convertible to ``T*`` and ``ndim == (-1 || other.ndim)``. @@ -119,7 +118,7 @@ Any two points p₁ and p₂ of types P₁ and P₂ are said *compatible* if the * Comparison - Two *compatible* points are comparable and totally ordered (:cpp:concept:`std::StrictTotallyOrdered`) using the lexicographical ordering. + Two *compatible* points are comparable and totally ordered (:cpp:concept:`std::totally_ordered`) using the lexicographical ordering. * Arithmetics diff --git a/doc/source/core/view/operators.rst b/doc/source/core/view/operators.rst index 4a95aea3..50cf2cba 100644 --- a/doc/source/core/view/operators.rst +++ b/doc/source/core/view/operators.rst @@ -25,7 +25,7 @@ Arithmetical .. code:: - + mln::image2d ima1 = ...; mln::image2d ima2 = ...; auto g1 = ima1 + ima2; @@ -383,10 +383,12 @@ Conditional 3. .. cpp:function:: auto ifelse(Image ima, Scalar s_if, Image ima2) 4. .. cpp:function:: auto ifelse(Image ima, Scalar s_if, Scalar s_else) - 1. Makes a view where for each pixel value evals to :cpp:expr:`out(p) = ima(p) ? ima1(p) : ima2(p)`. - 2. Makes a view where for each pixel value evals to :cpp:expr:`out(p) = ima(p) ? ima1(p) : s_else`. - 3. Makes a view where for each pixel value evals to :cpp:expr:`out(p) = ima(p) ? s_if : ima2(p)`. - 4. Makes a view where for each pixel value evals to :cpp:expr:`out(p) = ima(p) ? s_if : s_else`. + .. Sphinx CPP domain with texpr does not support ternary ops + + 1. Makes a view where for each pixel value evals to ``out(p) = (ima(p) ? ima1(p) : ima2(p))``. + 2. Makes a view where for each pixel value evals to ``out(p) = (ima(p) ? ima1(p) : s_else)``. + 3. Makes a view where for each pixel value evals to ``out(p) = (ima(p) ? s_if : ima2(p))``. + 4. Makes a view where for each pixel value evals to ``out(p) = (ima(p) ? s_if : s_else)``. :param ima: Input range @@ -396,7 +398,7 @@ Conditional .. code:: - + mln::image2d ima = ...; mln::image2d ima1 = ...; mln::image2d ima2 = ...; diff --git a/doc/source/core/view/transform.rst b/doc/source/core/view/transform.rst index 173e86a2..10a7ed90 100644 --- a/doc/source/core/view/transform.rst +++ b/doc/source/core/view/transform.rst @@ -5,7 +5,7 @@ Include :file:`` .. cpp:namespace:: mln::view -#. .. cpp:function:: auto transform(Image ima, UnaryFunction f) +#. .. cpp:function:: auto transform(Image ima, std::UnaryFunction f) #. .. cpp:function:: auto transform(Image ima, Image ima2, BinaryFunction f) 1. Makes a view from `ima` where for each pixel value evals to :cpp:expr:`out(p) = f(ima(p))` diff --git a/doc/source/labeling/cdt.rst b/doc/source/labeling/cdt.rst index 71997349..3b7d7e0a 100644 --- a/doc/source/labeling/cdt.rst +++ b/doc/source/labeling/cdt.rst @@ -80,6 +80,8 @@ Example with the 5-7-11 weights:: CDT with 5-7-11 :cpp:ref:`mln::wmask2d` (5-7-11 distance) + - + References ---------- diff --git a/doc/source/morpho.rst b/doc/source/morpho.rst index ed6681c2..3a30aabb 100644 --- a/doc/source/morpho.rst +++ b/doc/source/morpho.rst @@ -39,7 +39,7 @@ Segmentation Component Trees & Hierarchical Representations -********************************************* +********************************************** .. toctree:: :maxdepth: 1 diff --git a/doc/source/morpho/area_filter.rst b/doc/source/morpho/area_filter.rst index 89e5bccd..d1330e5e 100644 --- a/doc/source/morpho/area_filter.rst +++ b/doc/source/morpho/area_filter.rst @@ -6,8 +6,8 @@ Include :file:`` .. cpp:namespace:: mln::morpho .. cpp:function:: \ - Image{I} concrete_t area_opening(I f, Neighborhood nbh, int area, Compare cmp) - Image{I} concrete_t area_closing(I f, Neighborhood nbh, int area) + Image{I} image_concrete_t area_opening(I f, Neighborhood nbh, int area, Compare cmp) + Image{I} image_concrete_t area_closing(I f, Neighborhood nbh, int area) On binary images, the area connected opening that preserves connected diff --git a/doc/source/morpho/closing.rst b/doc/source/morpho/closing.rst index 532d1dcd..80e0ffae 100644 --- a/doc/source/morpho/closing.rst +++ b/doc/source/morpho/closing.rst @@ -6,8 +6,8 @@ Include :file:`` .. cpp:namespace:: mln::morpho .. cpp:function:: \ - Image{I} concrete_t closing(I image, StructuringElement se) - Image{I} concrete_t closing(I image, StructuringElement se, BorderManager bm) + Image{I} image_concrete_t closing(I image, StructuringElement se) + Image{I} image_concrete_t closing(I image, StructuringElement se, BorderManager bm) void closing(Image image, StructuringElement se, OutputImage out) void closing(Image image, StructuringElement se, BorderManager bm, OutputImage out) diff --git a/doc/source/morpho/dilation.rst b/doc/source/morpho/dilation.rst index 544fcca7..05bbeb98 100644 --- a/doc/source/morpho/dilation.rst +++ b/doc/source/morpho/dilation.rst @@ -9,8 +9,8 @@ Include :file:`` .. cpp:function:: \ - Image{I} concrete_t dilation(I image, StructuringElement se) - Image{I} concrete_t dilation(I image, StructuringElement se, BorderManager bm) + Image{I} image_concrete_t dilation(I image, StructuringElement se) + Image{I} image_concrete_t dilation(I image, StructuringElement se, BorderManager bm) void dilation(Image image, StructuringElement se, OutputImage out) void dilation(Image image, StructuringElement se, BorderManager bm, OutputImage out) diff --git a/doc/source/morpho/dynamic_filter.rst b/doc/source/morpho/dynamic_filter.rst index 049a9bac..ddc04e3f 100644 --- a/doc/source/morpho/dynamic_filter.rst +++ b/doc/source/morpho/dynamic_filter.rst @@ -6,8 +6,8 @@ Include :file:`` .. cpp:namespace:: mln::morpho .. cpp:function:: \ - Image{I} concrete_t dynamic_opening(I f, Neighborhood nbh, int h) - Image{I} concrete_t dynamic_closing(I f, Neighborhood nbh, int h) + Image{I} image_concrete_t dynamic_opening(I f, Neighborhood nbh, int h) + Image{I} image_concrete_t dynamic_closing(I f, Neighborhood nbh, int h) On grayscale images, the dynamic connected opening removes maxima whose diff --git a/doc/source/morpho/erosion.rst b/doc/source/morpho/erosion.rst index 63c06b43..804eb062 100644 --- a/doc/source/morpho/erosion.rst +++ b/doc/source/morpho/erosion.rst @@ -3,10 +3,11 @@ Erosion Include :file:`` +.. cpp:namespace:: mln::morpho .. cpp:function:: \ - Image{I} concrete_t erosion(I image, StructuringElement se) - Image{I} concrete_t erosion(I image, StructuringElement se, BorderManager bm) + Image{I} image_concrete_t erosion(I image, StructuringElement se) + Image{I} image_concrete_t erosion(I image, StructuringElement se, BorderManager bm) void erosion(Image image, StructuringElement se, OutputImage out) void erosion(Image image, StructuringElement se, BorderManager bm, OutputImage out) diff --git a/doc/source/morpho/extinction_transform.rst b/doc/source/morpho/extinction_transform.rst index 5251afea..6d8c11dd 100644 --- a/doc/source/morpho/extinction_transform.rst +++ b/doc/source/morpho/extinction_transform.rst @@ -6,8 +6,8 @@ Include :file:`` .. cpp:namespace:: mln::morpho .. cpp:function:: \ - Image{I} concrete_t minima_extinction_transform(I ima, Neighborhood nbh) - Image{I} concrete_t maxima_extinction_transform(I ima, Neighborhood nbh) + Image{I} image_concrete_t minima_extinction_transform(I ima, Neighborhood nbh) + Image{I} image_concrete_t maxima_extinction_transform(I ima, Neighborhood nbh) The notion of *extinction* of a local extremum is based on the h-extrema (see. :doc:`dynamic_filter`). The extinction value of a bassin corresponds its *dynamic* when it merges with another basin. diff --git a/doc/source/morpho/fill_hole.rst b/doc/source/morpho/fill_hole.rst index 7c9e0317..03a9f34d 100644 --- a/doc/source/morpho/fill_hole.rst +++ b/doc/source/morpho/fill_hole.rst @@ -6,7 +6,7 @@ Include :file:`` .. cpp:namespace:: mln::morpho .. cpp:function:: \ - Image{I} concrete_t fill_hole(I f, Neighborhood nbh, image_point_t marker) + Image{I} image_concrete_t fill_hole(I f, Neighborhood nbh, image_point_t marker) Image{I} void fill_hole(I f, Neighborhood nbh, image_point_t marker, Image out) The holes of a binary image correspond to the set of its regional minima which diff --git a/doc/source/morpho/gradient.rst b/doc/source/morpho/gradient.rst index 53e7b798..1ba6138c 100644 --- a/doc/source/morpho/gradient.rst +++ b/doc/source/morpho/gradient.rst @@ -6,9 +6,9 @@ Include :file:`` .. cpp:namespace:: mln::morpho .. cpp:function:: \ - Image{I} concrete_t gradient(I f, StructuringElement se) - Image{I} concrete_t external_gradient(I f, StructuringElement se) - Image{I} concrete_t internal_gradient(I f, StructuringElement se) + Image{I} image_concrete_t gradient(I f, StructuringElement se) + Image{I} image_concrete_t external_gradient(I f, StructuringElement se) + Image{I} image_concrete_t internal_gradient(I f, StructuringElement se) Compute the morphological gradients. Morphological gradients are operators enhancing variations of pixel intensity in a neighborhood diff --git a/doc/source/morpho/hit_or_miss.rst b/doc/source/morpho/hit_or_miss.rst index f5d6f68e..c00c1ae5 100644 --- a/doc/source/morpho/hit_or_miss.rst +++ b/doc/source/morpho/hit_or_miss.rst @@ -8,7 +8,7 @@ Include :file:`` .. cpp:namespace:: mln::morpho .. cpp:function:: \ - Image{I} concrete_t hit_or_miss(I image, StructuringElement se_hit, StructuringElement se_miss) + Image{I} image_concrete_t hit_or_miss(I image, StructuringElement se_hit, StructuringElement se_miss) void hit_or_miss(Image image, StructuringElement se_hit, StructuringElement se_miss, OutputImage out) The hit-or-miss transform is non-linerar filter used to detect pattern in diff --git a/doc/source/morpho/median_filter.rst b/doc/source/morpho/median_filter.rst index f0aa0f94..98979984 100644 --- a/doc/source/morpho/median_filter.rst +++ b/doc/source/morpho/median_filter.rst @@ -3,12 +3,14 @@ Median filter Include :file:`` +.. cpp:namespace:: mln::morpho + .. cpp:function:: \ void median_filter(Image image, StructuringElement se, BorderManager bm, OutputImage out) - Image{I} concrete_t median_filter(I image, StructuringElement se, BorderManager bm) + Image{I} image_concrete_t median_filter(I image, StructuringElement se, BorderManager bm) + - The median filter is non-linear filter that assigns the median value in a given structuring element 𝐵. .. math:: diff --git a/doc/source/morpho/opening.rst b/doc/source/morpho/opening.rst index e47f3333..ccbc1c96 100644 --- a/doc/source/morpho/opening.rst +++ b/doc/source/morpho/opening.rst @@ -6,8 +6,8 @@ Include :file:`` .. cpp:namespace:: mln::morpho .. cpp:function:: \ - Image{I} concrete_t opening(I image, StructuringElement se) - Image{I} concrete_t opening(I image, StructuringElement se, BorderManager bm) + Image{I} image_concrete_t opening(I image, StructuringElement se) + Image{I} image_concrete_t opening(I image, StructuringElement se, BorderManager bm) void opening(Image image, StructuringElement se, OutputImage out) void opening(Image image, StructuringElement se, BorderManager bm, OutputImage out) diff --git a/doc/source/morpho/opening_by_reconstruction.rst b/doc/source/morpho/opening_by_reconstruction.rst index 7bb79888..436a129c 100644 --- a/doc/source/morpho/opening_by_reconstruction.rst +++ b/doc/source/morpho/opening_by_reconstruction.rst @@ -8,12 +8,12 @@ Include :file:`` .. cpp:namespace:: mln::morpho .. cpp:function:: \ - Image{I1}\ - concrete_t opening_by_reconstruction(I1 f, I2 markers, Neighborhood nbh, Compare cmp) - Image{I1}\ - concrete_t opening_by_reconstruction(I1 f, I2 markers, Neighborhood nbh) - Image{I1}\ - concrete_t closing_by_reconstruction(I1 f, I2 markers, Neighborhood nbh) + template \ + image_concrete_t opening_by_reconstruction(I1 f, I2 markers, Neighborhood nbh, Compare cmp) + template \ + image_concrete_t opening_by_reconstruction(I1 f, I2 markers, Neighborhood nbh) + template \ + image_concrete_t closing_by_reconstruction(I1 f, I2 markers, Neighborhood nbh) The opening by reconstruction performs the reconstruction of the image ``markers`` under the constrain image ``f``. The markers designate the parts @@ -97,16 +97,16 @@ Example 2 : Dense region reconstruction * - .. figure:: /images/blobs2_binary.png - a. Original image + a\. Original image - .. figure:: /images/morpho_reconstruction_markers.png - b. Markers from the :doc:`rank_filter` + b\. Markers from the :doc:`rank_filter` - .. figure:: /images/morpho_reconstruction_dilated.png - c. Dilated of the original image *a* + c\. Dilated of the original image *a* .. literalinclude:: /snippets/reconstruction.cpp :start-after: M2_START @@ -126,7 +126,7 @@ get the objects in dense regions:: * - .. figure:: /images/morpho_reconstruction_rec.png - d. Reconstruction of *c* from the markers *b* + d\. Reconstruction of *c* from the markers *b* - .. figure:: /images/morpho_reconstruction_out.png diff --git a/doc/source/morpho/rank_filter.rst b/doc/source/morpho/rank_filter.rst index 6f7c3b40..cac72f0e 100644 --- a/doc/source/morpho/rank_filter.rst +++ b/doc/source/morpho/rank_filter.rst @@ -3,12 +3,14 @@ Rank filter Include :file:`` +.. cpp:namespace:: mln::morpho + .. cpp:function:: \ template void rank_filter(Image image, StructuringElement se, BorderManager bm, OutputImage out) - template concrete_t rank_filter(I image, StructuringElement se, BorderManager bm) + template image_concrete_t rank_filter(I image, StructuringElement se, BorderManager bm) + - The rank filter is non-linear filter that assigns the 𝑟-th value in a given structuring element 𝐵. .. math:: @@ -29,7 +31,7 @@ Include :file:`` :return: * (1) Nothing (the output image is passed as an argument) * (2) An image whose type is deduced from the input image - + :exception: N/A diff --git a/doc/source/morpho/tos.rst b/doc/source/morpho/tos.rst index 5305ba99..02fbe0b3 100644 --- a/doc/source/morpho/tos.rst +++ b/doc/source/morpho/tos.rst @@ -25,7 +25,7 @@ Include :file:`` .. rubric:: Requirements * ``image_value_t`` is a :cpp:concept:`UnsignedIntegral` - * ``image_domain_t`` is :cpp:class:`mln::box2d` or :cpp:class:`mln::box3d` + * ``image_domain_t`` is :cpp:any:`mln::box2d` or :cpp:any:`mln::box3d` .. rubric:: Example diff --git a/doc/source/ruminations/neighborhood.rst b/doc/source/ruminations/neighborhood.rst index 38f51295..5d219cbe 100644 --- a/doc/source/ruminations/neighborhood.rst +++ b/doc/source/ruminations/neighborhood.rst @@ -70,15 +70,9 @@ Algorithms that run with neighborhood * Convolution: can be separable -.. uml:: - - @startuml - abstract class WeightedNeighborhood { - } - - abstract class Neighborhood { - } +.. mermaid:: + classDiagram WeightedNeighborhood <|-- Neighborhood Neighborhood <|-- c4 Neighborhood <|-- c8 @@ -90,7 +84,6 @@ Algorithms that run with neighborhood Neighborhood <|-- diamond2d_1 Neighborhood <|-- diamond2d Neighborhood <|-- neighb2d - @enduml diff --git a/doc/source/tutorial.rst b/doc/source/tutorial.rst index 204bd8c1..99c7a00c 100644 --- a/doc/source/tutorial.rst +++ b/doc/source/tutorial.rst @@ -9,6 +9,5 @@ Quick Start tutorial/first_start.rst tutorial/using_algorithms.rst tutorial/writing_algorithms.rst - tutorial/extension.rst tutorial/views.rst diff --git a/doc/source/tutorial/first_start.rst b/doc/source/tutorial/first_start.rst index 64653867..7d5286ac 100644 --- a/doc/source/tutorial/first_start.rst +++ b/doc/source/tutorial/first_start.rst @@ -1,16 +1,17 @@ Creating and loading images =========================== +.. cpp:namespace:: mln Regular 2D images from scratch ------------------------------ -:cpp:any:`mln::image2d\` is the most-used image type representing images defined on a 2D grid. It is a template +:cpp:any:`image2d\ ` is the most-used image type representing images defined on a 2D grid. It is a template class, where the parameter `T` can be replaced by the type of value to store. For instance, if it is a grayscale image with values encoded on 8-bits unisgned integers, `T` will be `uint8_t`. For RGB-8 images, `T` is ``mln::rgb8``. Any -*regular* (foundamental) type can be used, fixed-size scalar and floating-point types are already defined in C++ in -the ` `_ header. The template parameter `T` is that we call -the *value type* (every image has a *value type*, be it static or dynamic) +*regular* (foundamental) type can be used, fixed-size scalar and floating-point types are already defined in C++ in the +` `_ header. The template parameter `T` is that we call the +*value type* (every image has a *value type*, be it static or dynamic) An image might be created from a set of values (this is generally used only for testing an algorithm). For instance, in @@ -34,7 +35,7 @@ value, e.g. the grayscale value 128:: Finally a 2D image may not start at location `(0,0)`. For instance when want to work a sub-regions of an image, the -location of the origin has moved. Every image is a tied to a *domain*, which is a :cpp:class:`box2d` for 2D images. +location of the origin has moved. Every image is a tied to a *domain*, which is a :cpp:any:`box2d` for 2D images. One can initialize an image from a domain of a pair *(width, height)*:: // A roi (x=50,y=50,w=100,h=100) @@ -44,8 +45,9 @@ One can initialize an image from a domain of a pair *(width, height)*:: Regular ND images ----------------- -The class :cpp:class:`image2d` is generalized in any dimension (:cpp:class:`image1d`, :cpp:class:`image3d` and -so on). Actually, they are aliases over the type (:cpp:class:`__ndbuffer_image` where the dimension is fixed). +The class :cpp:any:`image2d` is generalized in any dimension (:cpp:any:`image1d`, :cpp:any:`image3d` and so +on). Actually, they are aliases over the type (:cpp:any:`ndimage\ <__ndbuffer_image>` where the +dimension is fixed). Thus you can create 3D-images from a initializer-lists:: @@ -63,7 +65,7 @@ From a triplet (width,height,depth):: // Create a 800x600 2D images mln::image2d f(128, 128, 128); -From a :cpp:class:`box3d` domain:: +From a :cpp:any:`box3d` domain:: // A roi (x=50,y=50,z=50,w=100,h=100,d=100) mln::box2d roi = {{50,50,50}, {150,150,150}}; @@ -95,7 +97,7 @@ Images from existing data In your application, would will mostly want to use algorithms from many libraries that do not share the image types. As soon as an image is encoded as C raw-buffer of data, you will be able to exchange images from/to pylene using -:cpp:func:`mln::__ndbuffer_image::from_buffer`. +:cpp:any:`__ndbuffer_image::from_buffer`. :: @@ -127,5 +129,6 @@ And you can access the Pylene internal buffer with :cpp:func:`buffer `_ * `Boost `_ * `Range-v3 `_ +* `FreeImage `_ +* `Fmt `_ -It also depends on *FreeImage* which can be installted with your package manager on most distribution. The packages are -generally named `freeimage` and `freeimage-devel`. There are three ways to install the C++ Pylene: @@ -22,8 +22,17 @@ There are three ways to install the C++ Pylene: * The preferred and strongly recommended way to use Pylene is using Conan, a C++ package manager that would handle the dependencies. * The other way is using installing the libraries from sources. +In all cases, you have to install *boost* and *FreeImage* using your system package manager. + .. highlight:: shell +Pre-installation +---------------- + +Install *FreeImage* and *Boost* with the system package manager of your distribution. +The packages are generally named `freeimage`, `freeimage-devel`, and `boost-devel` + + Install from sources -------------------- @@ -162,7 +171,7 @@ Installation (for developers) Sample project structure using Pylene ------------------------------------- -See `https://gitlab.lrde.epita.fr/olena/pylene/-/blob/master/test_package/`_. +See ``_. * :file:`conanfile.txt`:: @@ -185,9 +194,9 @@ See `https://gitlab.lrde.epita.fr/olena/pylene/-/blob/master/test_package/`_. * Build intructions:: - mkdir build && cd build - conan install .. -g cmake_find_package - cmake .. + mkdir build && cd build + conan install .. -g cmake_find_package + cmake .. diff --git a/doc/source/tutorial/using_algorithms.rst b/doc/source/tutorial/using_algorithms.rst index ce8cdfed..dac077e3 100644 --- a/doc/source/tutorial/using_algorithms.rst +++ b/doc/source/tutorial/using_algorithms.rst @@ -4,10 +4,12 @@ Using algorithms Using the library is straighforward. Many ready-to-use algorithm just takes images as input and returns an image. Consider the algorithm :cpp:func:`mln::morpho::dilation`. In its simplest form, this algorithm -takes an image, a structuring element and returns an image, ``dilation(in, se) -> out`:: +takes an image, a structuring element and returns an image, ``dilation(in, se) -> out``:: #include - #include + #include + #include mln::image2d input; mln::io::imread("input.tiff", input); @@ -17,3 +19,25 @@ takes an image, a structuring element and returns an image, ``dilation(in, se) - + +Output image convention +----------------------- + + +Most algorithms have two versions: + +#. ``out = algo(in)`` where the output image is allocated by the algorithm and returned +#. ``algo(in, out)`` where the user has to provide the output image + +Usually, the first version allocates and forward to the second version. The previous snippet of code is equivalent to:: + + mln::image2d input; + mln::io::imread("input.tiff", input); + + mln::image2d output(input.width(), input.height); + mln::morpho::dilation(input, mln::se::disc(5), output); + mln::io::imsave(output, "out.tiff"); + + + + diff --git a/doc/source/tutorial/writing_algorithms.rst b/doc/source/tutorial/writing_algorithms.rst index 9e3ecb46..47082055 100644 --- a/doc/source/tutorial/writing_algorithms.rst +++ b/doc/source/tutorial/writing_algorithms.rst @@ -1,148 +1,182 @@ -Traversing and accessing image values -------------------------------------- +Writing algorithms +================== -Accessing image values -^^^^^^^^^^^^^^^^^^^^^^ +Non-generic implementation +************************** -Most standard image types (see :concept:`Accessible Image`) supports -accessing a value though its point:: +Even if Pylene have algorithms written in a generic way as much as possible, you do **not** have to write generic +algorithms yourself if do not need so (nevertheless, we will see that it is not that difficult to do so). - mln::image2d f = { {1,2,3}, {4,5,6} }; - mln::point2d p = {1,1}; - std::cout << f(p) << "\n"; // Affiche 5 +Working on 2D/3D images +----------------------- -Note that indexes are in the order `(row, col)`. `(0,0)` refers to the -topleft corner and `(1,2)` to the bottom-right corner. +You can always use the two/three nested loop to iterate over all positions in the domain. You can access the value +of an :cpp:any:`mln::ndimage` at a given position `p=(x,y)` ou `p=(x,y,z)` with ``ima({x,y})`` or ``ima({x,y,z})``. -For 2D image, an equivalent writing is with :cpp:func:`image2d::at_`:: - mln::image2d f = { {1,2,3}, {4,5,6} }; - std::cout << f.at_(1,1) << "\n"; // Affiche 5 +:: + + auto roi = ima.domain(); + int x0 = roi.x(); + int y0 = roi.y(); + for (int y = 0; y < roi.height(); ++y) + for (int x = 0; x < roi.width(); ++x) + ima({x0 + x, y0 + y}); + -.. note:: - There are some first differences with Milena_: - - * First the range for the domain in Milena_ is closed, - (i.e. `domain = [pmin,pmax]`), here it is half-open to follow the - usual convention of the C++ standard library, so it is `domain = - [pmin,pmax)` and `pmax` is not included in the range. - - * Second, every image ``f`` in Milena_ supports ``f(p)`` where - ``p`` is point of the domain. This is not always the case with - this library as we provide more flexible ways to iterate on images. - -Traversing images -^^^^^^^^^^^^^^^^^ - -Most images (more precisely :concept:`Forward Image`) provide 3 ways -of traversing. - -* Iterating on *points* through the *domain* -* Iterating on *values* -* Iterating on *pixels* - -As a consequence, such an image ``f`` provide: - -* ``f.domain()`` The range of the image *points* -* ``f.values()`` The range of the image *values* -* ``f.pixels()`` The range of the image *pixels* - -An image can be birectional (see :concept:`Bidirectional Image`) and -allows to be traversed in the reverse order. In that case, the -*ranges* are bidirectional as well. Below is an example of image traversal. - -.. literalinclude:: /snippets/first_start_1.cpp - -It produces the following output. - -.. code-block:: none - - == Traversing forward == - Traversing through points. - [0,0]:1 - [0,1]:2 - [0,2]:3 - [1,0]:4 - [1,1]:5 - [1,2]:6 - Traversing on values. - 1 - 2 - 3 - 4 - 5 - 6 - Traversing with pixels. - [0,0]:1 - [0,1]:2 - [0,2]:3 - [1,0]:4 - [1,1]:5 - [1,2]:6 - - == Traversing backward == - Traversing through points. - [1,2]:6 - [1,1]:5 - [1,0]:4 - [0,2]:3 - [0,1]:2 - [0,0]:1 - Traversing on values. - 6 - 5 - 4 - 3 - 2 - 1 - Traversing with pixels. - [1,2]:6 - [1,1]:5 - [1,0]:4 - [0,2]:3 - [0,1]:2 - [0,0]:1 -.. note:: - Contrary to Milena_, the ordering of the traversal of images is - defined. Domains are *ordered* ranges. This means there is a - **total order** on *point* type. In the case of - :cpp:class:`mln::point2d`, this is the lexicographical order - (i.e., the natural scan order of 2D grids). Traversing with *value* - or *pixel* range follows the same order. +Reference semantic and passing images to functions +-------------------------------------------------- -Traversing with ranges and iterators -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +All images in Pylene have reference semantics. It means that the copy/move constructor and assignment operators do not +create real copies but alias the same image:: -The underlying concepts behind multidimensional ranges. They are like -normal C++ ranges but have a different interface to enable faster traversal. This is why, you -cannot use a normal `for` on these ranges but ``mln_foreach``. + mln::image2d A = {{1,2,3},{4,5,6}}; + mln::image2d B = A; // B aliases A + B({0,0}) = 42; // Writes on B, write on A + assert(A({0,0}) == 42); - mln_foreach(auto px, f.pixels()) - std::cout << px.point() << " : ' << px.val() << "\n"; +Therefore, copying image (in the C++ sense) are cheap and incur low overhead. Thus, images **should be passed by copy to +functions** and not by const-reference. + .. note:: - Contrary to Milena_ with do not provide *proxy iterators* as it is - more common to directly iterate with ``mln_foreach`` on values. + A good function signature for passing images:: + + void foo(mln::image2d input, mln::image out) + + Bad:: + + void foo(const mln::image2d& input, mln::image& out) + + +Algorithms with local information +--------------------------------- + +Many algorithms (especially in Mathematical Morphology) have to work with neighborhood that defines a connection between +pixels. For example, in 2D, you may want to use 4-connectivity or 8-connectivity for connected component labeling. + + +:ref:doc:`Neighborhoods and structuring elements ` are range generators. The expression `nbh(x)` +generates a set of points from an anchor (a point) `x`. The following snippet visit all :ref:doc:`4-connected +` neighbors of all points of an image:: + + for (int y = 0; y < roi.height(); ++y) + for (int x = 0; x < roi.width(); ++x) + for (mln::point2d n : mln::c4({x,y})) + if (n.x() >= 0 && n.x() < roi.width() && n.y() >= 0 && n.y() < roi.height()) + // Do something with n + + +Generic implementation +********************** + +Traversing an image in a generic ways, i.e. that is actually independant on the number of coordinates, is actually +simpler than the hand-made loop. Most images provide range-based facilities to allow to iterate over the +points (site coordinates) or the values of an image (or both). + +* `ima.domain()` returns a range of point +* `ima.values()` returns the range of values of the image +* `ima.pixels()` returns the range of pixels where a pixel is simply a pair *(point,value)* accessible with `px.point()` + and `px.val()`. + + +Summing the values of an image with point-access:: + + int sum = 0; + mln_foreach(auto p, ima.domain()) + sum += ima(p); + +with values:: + + int sum = 0; + mln_foreach(uint8_t v, ima.values()) + sum += v; + + +with pixels:: + + int sum = 0; + mln_foreach(auto px, ima.pixels()) + sum += px.val(); + +.. important:: + To iterate over the values of a range in Pylene, you have to use ``mln_foreach(auto x, rng)`` which has the same + semantics as ``for(auto x : rng)`` but supports :ref:doc:`multi-dimensional ranges `. -Traversing several images in the same time -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Neighborhoods and structuring elements in a generic context +----------------------------------------------------------- -Image and range views enable to pack (zip) several objects in a single object:: +Using neighborhood in a generic context is actually easier than in a non-generic one. Compare the following +implementation with the previous one that visit every neighbor of all point in region. The following code is able +to work witn any compatible neighborhood (ie. 4-connectivity or 8-connectivity in 2D, 6-/26-connectivity in 3D...). Yet +the code is simpler, more resuable and just as efficient:: + + auto roi = ima.domain(); + mln_foreach(auto p, roi) + for (auto n : nbh(p)) + if (roi.has(n)) + // Do something with n + + + + +Accessing multiple images +------------------------- + +The straightforward way to access values from multiple is to iterate over a domain and to use direct image access:: + + mln_foreach(auto p, domain) + // Use f(p) and f(g) + + + +However, it might be more efficent to avoid a *point to index* computation at each turn. Range views enable to pack +(zip) several objects in a single object and iterate in a more efficient way:: auto vals_1 = f.values(); auto vals_2 = g.values(); mln_foreach((auto [v1, v2]), mln::ranges::view::zip(vals_1, vals_2)) ... -You can also iterate using a domain is the image supports direct access by points:: - mln_foreach(auto p, domain) - // Use f(p) and f(g) +Generic signature and concept checking +-------------------------------------- + +A simple but not optimal generic implementation of a dilation would look like:: + + + template + requires (mln::concepts::Image && + mln::concepts::OutputImage && + mln::concepts::StructuringElement> && + std::same_as, image_point_t> && + std::convertible_to, image_value_t>) + void dilation(I input, SE se, J out) + { + auto roi = ima.domain(); + mln_foreach(auto p, roi) + { + auto m = input(p); + for (auto n : se(p)) + if (roi.has(n)) + m = std::max(m, input(n)) + out(p) = m; + } + } + + + + + + + + + diff --git a/pylene/include/mln/core/image/ndimage_fwd.hpp b/pylene/include/mln/core/image/ndimage_fwd.hpp index e0dc50ef..3c58914f 100644 --- a/pylene/include/mln/core/image/ndimage_fwd.hpp +++ b/pylene/include/mln/core/image/ndimage_fwd.hpp @@ -16,4 +16,8 @@ namespace mln template using image3d = mln::__ndbuffer_image; + + + template + using ndimage = mln::__ndbuffer_image; } -- GitLab From 1e193b4f3b816997cefdb03be17d193d5f31e9e5 Mon Sep 17 00:00:00 2001 From: Edwin Carlinet Date: Thu, 9 Jul 2020 16:43:06 +0200 Subject: [PATCH 4/6] Add ref to the cppstd with conan in the doc. --- .gitlab-ci.yml | 10 +++++----- README.md | 4 ++-- doc/source/tutorial/installation.rst | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a624e2b9..8d9234c9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -36,7 +36,7 @@ windows-debug: stage: build script: - mkdir build; cd build - - conan install .. -s build_type=Debug --build missing + - conan install .. -s build_type=Debug --build missing -s compiler.cppstd=20 - cmake .. -G Ninja -DCMAKE_BUILD_TYPE=debug -D CMAKE_TOOLCHAIN_FILE="C:\vcpkg\scripts\buildsystems\vcpkg.cmake" - cmake --build . --target build-tests - ctest -L UnitTests --schedule-random --output-on-failure @@ -59,7 +59,7 @@ windows-debug: stage: build script: - mkdir build && cd build - - conan install .. --build missing -e CXXFLAGS="" -e CCFLAGS="" -pr $CONAN_PROFILE + - conan install .. --build missing -s compiler.cppstd=20 -e CXXFLAGS="" -e CCFLAGS="" -pr $CONAN_PROFILE - cmake -G Ninja .. -DCMAKE_BUILD_TYPE=$PYLENE_CONFIGURATION -DSANITIZE_ADDRESS=$ASAN -DSANITIZE_MEMORY=$MSAN -DSANITIZE_UNDEFINED=$UBSAN - cmake --build . --target Pylene - cmake --build . --target build-tests @@ -177,7 +177,7 @@ distcheck-linux-coverage: stage: bench script: - mkdir build && cd build - - conan install .. -pr gcc-9 --build missing + - conan install .. -pr gcc-9 --build missing -s compiler.cppstd=20 - cmake -G Ninja .. -DCMAKE_BUILD_TYPE=Release - cmake --build . --target fetch-external-data - cmake --build . --target build-bench @@ -210,7 +210,7 @@ distbench-linux-gcc9-release: stage: build script: - mkdir build && cd build - - conan install -u .. -pr gcc-9 --build missing + - conan install -u .. -pr gcc-9 --build missing -s compiler.cppstd=20 - cmake -G Ninja .. -DCMAKE_BUILD_TYPE=Release - cmake --build . --target build-doc - mkdir ../public && mv doc/sphinx/* ../public/ @@ -243,7 +243,7 @@ package: script: - mkdir build && cd build - conan user carlinet -r lrde-public -p $CONAN_LRDE_API_KEY - - conan create .. $CONAN_USER/$PACKAGE_TAG -pr gcc-9 --build missing -e CXX=g++ -e CC=gcc + - conan create .. $CONAN_USER/$PACKAGE_TAG -pr gcc-9 --build missing -s compiler.cppstd=20 -e CXX=g++ -e CC=gcc - conan upload -r lrde-public --all $PACKAGE_NAME/$PACKAGE_VERSION@$CONAN_USER/$PACKAGE_TAG rules: - if: $CI_COMMIT_BRANCH == "master" || $CI_COMMIT_BRANCH == "development/cpp20" diff --git a/README.md b/README.md index b4ee9726..0e90dbf5 100644 --- a/README.md +++ b/README.md @@ -45,10 +45,10 @@ library by other means, refer to the [documentation](http://olena.pages.lrde.epi conan remote add lrde-public https://artifactory.lrde.epita.fr/artifactory/api/conan/lrde-public ``` -1. Install the library with Conan: +1. Install the library with Conan (with C++20 standard) ``` -conan install pylene/head@lrde/stable -g cmake_find_package +conan install pylene/head@lrde/stable -g cmake_find_package -s compiler.cppstd=20 ``` 2. Edit your ``CMakeLists.txt`` to include the paths to the library: diff --git a/doc/source/tutorial/installation.rst b/doc/source/tutorial/installation.rst index 23358474..cc634e67 100644 --- a/doc/source/tutorial/installation.rst +++ b/doc/source/tutorial/installation.rst @@ -49,7 +49,7 @@ Download the latest release from `Pylene Gitlab `_. * Build intructions:: mkdir build && cd build - conan install .. -g cmake_find_package + conan install .. -g cmake_find_package -s compiler.cppstd=c++20 cmake .. -- GitLab From 5163f85afbf5d05be2fc3bc778e2adaff000e9b8 Mon Sep 17 00:00:00 2001 From: Edwin Carlinet Date: Thu, 9 Jul 2020 18:08:43 +0200 Subject: [PATCH 5/6] [ci_skip] Add community guidelines. --- doc/source/community.rst | 21 +++++++++++++++++++++ doc/source/index.rst | 1 + 2 files changed, 22 insertions(+) create mode 100644 doc/source/community.rst diff --git a/doc/source/community.rst b/doc/source/community.rst new file mode 100644 index 00000000..bcfed2ba --- /dev/null +++ b/doc/source/community.rst @@ -0,0 +1,21 @@ +Community guidelines +==================== + +Report issues or problems with the software +------------------------------------------- + +If you have any trouble with the library, any question and so on; you may open an issue on gitlab: + +https://gitlab.lrde.epita.fr/olena/pylene/-/issues + + +Contributing to the software +---------------------------- + +To submit a patch, a feature, you have to: + +1. Create a user account on https://gitlab.lrde.epita.fr +2. Fork the project +3. Create a pull request + + diff --git a/doc/source/index.rst b/doc/source/index.rst index 4721c71a..03a454c0 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -25,6 +25,7 @@ Mathematical Morphology Operators). Introduction tutorial + community Reference Manual Developer Manual -- GitLab From 363432dfeb83824bb3a70ee63cc8614a0b53ce28 Mon Sep 17 00:00:00 2001 From: Edwin Carlinet Date: Thu, 9 Jul 2020 18:26:18 +0200 Subject: [PATCH 6/6] [ci_skip] Add authors. --- AUTHORS | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 AUTHORS diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..64ad6d11 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,25 @@ +Main authors +============ + +Edwin Carlinet (maintainer) +Michaël Roynard + + +Contributions +============= + +Célian Gossec +Virgile Hirtz + + + +Main past authors from Milena having influenced the library +=========================================================== + +Thierry Géraud +Roland Levillain +Guillaume Lazzara + + + + -- GitLab