Commit a9eb755c authored by Baptiste Esteban's avatar Baptiste Esteban
Browse files

Start the documentation of the MToS

parent 2ca84043
......@@ -47,6 +47,7 @@ Component Trees & Hierarchical Representations
morpho/component_tree
morpho/maxtree
morpho/tos
morpho/multivariate_component_tree
morpho/alphatree
morpho/watershed_hierarchy
......
Multivariate Component Tree
===========================
The component trees have been extended for multivariate images [Car19]_. Right
now, only the multivariate tree of shapes [Car15]_ (MToS) has been implemented in
Pylene.
* Include :file:`<mln/morpho/mtos.hpp>`
.. cpp:namespace:: mln::morpho
.. cpp:function:: auto mtos(image2d<rgb8> ima, point2d pstart);
Compute the multivariate tree of shapes and returns a pair `(tree, node_map)`.
See :doc:`component_tree` for more information about the representation of tree.
:param ima: The input image in RGB format.
:param pstart: The rooting point
:return: A tree of type ``component_tree<void>`` (no values are related to the nodes of the tree since they do not have a unique value) and a map from image point to node tree.
Notes
-----
* Before computing the MToS, the user should add a border to the image, with the values of this border set to the median value of the border of the original image
* The resulting nodemap is sixteen times bigger than the original image. The user is advised to reduce the nodemap before doing any processing. (**FIXME** to keep ?)
Example
-------
This example computes a grain filter, which removes all the node which have an area inferior to 100.
::
#include <mln/accu/accumulators/count.hpp>
#include <mln/core/image/ndimage.hpp>
#include <mln/morpho/mtos.hpp>
#include <mln/io/imread.hpp>
// Function to reduce the nodemap to the original image domain
mln::image2d<int> reduce_nodemap(mln::image2d<int> n);
// Function to add a border
mln::image2d<mln::rgb8> add_border(mln::image2d<mln::rgb8> ima);
// Function to remove the border
mln::image2d<int> remove_border(mln::image2d<int> n);
// Accumulator to compute the mean of each node, without taking into account the values of the holes
// (it only takes into account the value of the connected component related to a node)
struct mean_node_accu : mln::Accumulator<mean_node_accu>
{
using result_type = decltype(std::declval<mln::rgb8>() + std::declval<mln::rgb8>());
public:
template <typename Pix>
void take(const Pix& pix)
{
m_sum += pix.val();
m_count++;
}
void take(const mean_node_accu&) {}
result_type to_result() const { return m_count > 1 ? static_cast<result_type>(m_sum / m_count) : m_sum; }
private:
result_type m_sum = {0, 0, 0};
int m_count = 0;
};
int main(void)
{
mln::image2d<mln::rgb8> ima;
mln::io::imread("lena.ppm", ima);
// Add a border
auto to_process = add_border(ima);
// Compute the MToS
auto [t, nm] = mln::morpho::mtos(to_process, {0, 0});
// Reduce the nodemap
nm = reduce_nodemap(nm);
// Remove the border in the nodemap
nm = remove_border(nm);
// Compute the area of each node of the tree
auto area = t.compute_attribute_on_points(nm, mln::accu::accumulators::count<int>());
// Perform a grain filter on the tree
t.filter(mln::morpho::CT_FILTER_DIRECT, nm, [&area](int n) { return area[n] >= 100; });
// Compute the mean of the connected component of each nodes
auto mean = t.compute_attribute_on_pixels(nm, ima, mean_node_accu());
// Reconstruct the tree
auto rec = t.reconstruct_from(nm, ranges::make_span(mean.data(), mean.size()));
return 0;
}
.. list-table::
* - .. image:: /images/depth_map.png
:width: 100%
- .. image:: /images/mtos_rec.png
:width: 100%
* - The depth map resulting of the fusion of the trees
- The reconstructed image from the filtered tree
References
----------
.. [Car19] Edwin Carlinet and Thierry Géraud (2019). Introducing Multivariate Connected Openings and Closings. *International Symposium on Mathematical Morphology and Its Applications to Signal and Image Processing.* Springer, Cham. 215-227
.. [Car15] Edwin Carlinet and Thierry Géraud (2015). MToS: A tree of shapes for multivariate images. *IEEE Transactions on Image Processing 24.12* 5330-5342
\ No newline at end of file
......@@ -82,6 +82,14 @@ namespace
return res;
}
mln::image2d<int> remove_border(mln::image2d<int> n)
{
mln::image2d<int> res(n.width() - 2, n.height() - 2);
mln_foreach(auto p, res.domain())
res(p) = n(p + mln::point2d{1, 1});
return res;
}
/// \brief Compute the maximum value of an image
std::uint16_t max(mln::image2d<std::uint16_t> ima)
{
......@@ -118,7 +126,7 @@ int main(int argc, char* argv[])
mln::image2d<mln::rgb8> ima;
mln::io::imread(argv[1], ima);
ima = add_border(ima);
auto to_process = add_border(ima);
mln::morpho::component_tree<> trees[3];
mln::image2d<int> nodemaps[3];
......@@ -126,7 +134,7 @@ int main(int argc, char* argv[])
for (int c = 0; c < 3; c++)
{
std::tie(trees[c], nodemaps[c]) = mln::morpho::tos(mln::view::channel(ima, c), {0, 0});
std::tie(trees[c], nodemaps[c]) = mln::morpho::tos(mln::view::channel(to_process, c), {0, 0});
depths[c] = trees[c].compute_depth();
}
......@@ -143,9 +151,10 @@ int main(int argc, char* argv[])
auto [t, nm] = mln::morpho::details::satmaxtree(depth_map);
nm = reduce_nodemap(nm);
auto mean = t.compute_attribute_on_pixels(nm, ima, mean_node_accu());
nm = remove_border(nm);
auto area = t.compute_attribute_on_points(nm, mln::accu::accumulators::count<int>());
t.filter(mln::morpho::CT_FILTER_DIRECT, nm, [&area](int n) { return area[n] >= 100; });
auto mean = t.compute_attribute_on_pixels(nm, ima, mean_node_accu());
auto rec = t.reconstruct_from(nm, ranges::make_span(mean.data(), mean.size()));
mln::io::imsave(mln::view::cast<mln::rgb8>(rec), argv[3]);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment