Commit 802747af authored by Quentin Kaci's avatar Quentin Kaci
Browse files

Merge branch 'development/watershed-hierarchy-saliency-integration' of...

Merge branch 'development/watershed-hierarchy-saliency-integration' of https://gitlab.lrde.epita.fr/olena/pylene into development/watershed-hierarchy-saliency-integration
parents 324675ca 7a9fea56
Pipeline #28624 failed with stage
in 26 minutes and 28 seconds
......@@ -294,6 +294,18 @@ to make an horizontal cut of this tree.
:param nodemap: An image thats maps ``point -> node id``
:param levels: (Optional) The altitude of each node in the tree (for example the :math:`\alpha` associated to each node for the alphatree).
Saliency Computation
--------------
It is also possible to compute the saliency map to obtain another visualization.
.. cpp:function:: auto saliency(Image node_map)
Compute and return the saliency map of the tree.
:param node_map: An image thats maps ``point -> node id``
:return: The saliency map as an image
A complete example
------------------
......
......@@ -125,18 +125,12 @@ namespace mln::morpho
template <class I, class V>
image_ch_value_t<I, V> reconstruct_from(I node_map, ::ranges::span<V> values) const;
using Edge = std::tuple<int, int, double>;
/// Generate a saliency map of the given Component Tree
/// \brief Produce a visualization of the given Component Tree using the Khalimsky grid of the saliency map
///
/// @return A list of edges that associates each edges to a saliency weight
template <class I, class J>
std::vector<Edge> saliency_map(I node_map, J values);
/// Produce a visualization of the given Component Tree using the Khalimsky grid of the saliency map
template <class I, class J>
mln::image2d<double> saliency_khalimsky_grid(I node_map, J values);
/// \param node_map Image point -> node_id mapping
template <class I>
mln::image2d<double> saliency(I node_map);
using node_t = int;
......@@ -429,8 +423,8 @@ namespace mln::morpho
using Edge = std::tuple<int, int, double>;
template <class I, class J>
std::vector<Edge> component_tree<void>::saliency_map(I node_map, J values)
template <class I>
std::vector<Edge> saliency_map(I node_map)
{
std::vector<Edge> res;
......@@ -442,20 +436,6 @@ namespace mln::morpho
{
if ((q[0] == p[0] + 1 || q[1] == p[1] + 1) && q[0] < node_map.width() && q[1] < node_map.height())
{
auto id_p = 0;
auto id_q = 0;
for (size_t i = 1; i < this->parent.size(); i++)
{
if (id_p == 0 && values[i] == node_map(p))
id_p = i;
if (id_q == 0 && values[i] == node_map(q))
id_q = i;
if (id_p != 0 && id_q != 0)
break;
}
auto edge = std::make_tuple(p[0] + width * p[1], q[0] + width * q[1], 0);
std::get<2>(edge) = std::abs(node_map(p) - node_map(q));
......@@ -468,8 +448,8 @@ namespace mln::morpho
return res;
}
template <class I, class J>
mln::image2d<double> component_tree<void>::saliency_khalimsky_grid(I node_map, J values)
template <class I>
mln::image2d<double> component_tree<void>::saliency(I node_map)
{
int height = node_map.height();
int width = node_map.width();
......@@ -480,7 +460,7 @@ namespace mln::morpho
image2d<double> res(res_width, res_height);
fill(res, 0);
const std::vector<Edge>& s_map = this->saliency_map(node_map, values);
const std::vector<Edge>& s_map = saliency_map(node_map);
for (const auto& edge : s_map)
{
......
......@@ -22,6 +22,7 @@ add_core_test(${test_prefix}depth_first depthfirst.cpp)
add_core_test(${test_prefix}maxtree maxtree.cpp)
add_core_test(${test_prefix}alphatree alphatree.cpp)
add_core_test(${test_prefix}private_directional_hqueue directional_hqueue.cpp)
add_core_test(${test_prefix}component_tree component_tree.cpp)
target_link_libraries(${test_prefix}dilate PRIVATE TBB::TBB)
#include <gtest/gtest.h>
#include <iostream>
#include <mln/core/image/ndimage.hpp>
#include <mln/io/imread.hpp>
#include <mln/io/imsave.hpp>
#include <mln/morpho/component_tree.hpp>
#include <mln/morpho/tos.hpp>
TEST(Component_tree, Saliency_Map)
{
mln::image2d<uint8_t> img = {{0, 0, 100, 0}, {0, 0, 75, 0}, {95, 80, 60, 0}, {0, 0, 0, 0}};
int expected_s_map_val[24][3] = {{0, 1, 0}, {0, 4, 0}, {1, 2, 100}, {1, 5, 0}, {2, 3, 100}, {2, 6, 25},
{3, 7, 0}, {4, 5, 0}, {4, 8, 95}, {5, 6, 75}, {5, 9, 80}, {6, 7, 75},
{6, 10, 15}, {7, 11, 0}, {8, 9, 15}, {8, 12, 95}, {9, 10, 20}, {9, 13, 80},
{10, 11, 60}, {10, 14, 60}, {11, 15, 0}, {12, 13, 0}, {13, 14, 0}, {14, 15, 0}};
auto [t, node_map] = mln::morpho::tos(img, {0, 0});
const std::vector<mln::morpho::Edge>& s_map = mln::morpho::saliency_map(img);
for (int i = 0; i < 24; ++i)
{
auto expected_edge = expected_s_map_val[i];
ASSERT_EQ(expected_edge[2], std::get<2>(s_map[i]));
}
}
TEST(Component_tree, Saliency)
{
mln::image2d<uint8_t> img = {{0, 0, 100, 0}, {0, 0, 75, 0}, {95, 80, 60, 0}, {0, 0, 0, 0}};
int expected_saliency[9 * 9] = {255, 255, 255, 255, 155, 255, 155, 255, 255, //
255, 255, 255, 255, 155, 255, 155, 255, 255, //
255, 255, 255, 255, 155, 230, 155, 255, 255, //
255, 255, 255, 255, 180, 255, 180, 255, 255, //
160, 160, 160, 175, 175, 240, 180, 255, 255, //
255, 255, 240, 255, 235, 255, 195, 255, 255, //
160, 160, 160, 175, 175, 195, 195, 255, 255, //
255, 255, 255, 255, 255, 255, 255, 255, 255, //
255, 255, 255, 255, 255, 255, 255, 255, 255};
auto [t, node_map] = mln::morpho::tos(img, {0, 0});
auto saliency = t.saliency(img);
for (int i = 0; i < 9 * 9; ++i)
{
ASSERT_EQ(expected_saliency[i], static_cast<int>(saliency({i % 9, i / 9})));
}
}
\ No newline at end of file
Supports Markdown
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